Lots of updates for net-next for this cycle. As usual, we have
a lot of small fixes and cleanups, the bigger items are: * proper mac80211 rate control locking, to fix some random crashes (this required changing other locking as well) * mac80211 "fast-xmit", a mechanism to reduce, in most cases, the amount of code we execute while going from ndo_start_xmit() to the driver * this also clears the way for properly supporting S/G and checksum and segmentation offloads -----BEGIN PGP SIGNATURE----- iQIcBAABCAAGBQJVSh65AAoJEDBSmw7B7bqrudwP/0iXyNQhF0mLTENrx+rdsDZS qQhB/8wejJaOJb89Re7M+bhwri7Q6S5BM/G24vhMc01dxmqNMcdKfEV3+nlmc5C+ KeEgTI9aZiCnUt4WAd54Zwbkc9o+1kBtaFuaWDvOdQHUf0WDwEIQxjnV4+SZujV9 xl1TV5yV35hRQgrDE8ZSbtOYRmhSVoi0MEgwqAjzdN2fEPyWVeqwYULDtpOopjL2 UHQgv0E2fYVRWennHyQQ88tWBQg+EsRaG1U1/rYHhNBmAJ+f9AOxKi7ErzxYfkbM 961B+3E++pM+zUeqw6+jaMKqT5jeCCM5ugCNSG4NrIvfxDIDgecAFV9Fs2islnI4 8xd3GqyA5iqaitAWIUsaYaQfaAcwSIlpSinfQW9EUm2wuCkPyZboFP+GRd2K7sQn FnRJSJ9PkGPdWwdDE3gunLHBHtbDS0z+R8VegIeS0qT8LamkqICiNQSyPlsTeluW ig2kwHsDdj3k11wyelhfp/RdtsOch/brKpLSjdzPXC1BzIWhQLwmsPh9qZ83vSB9 qbLsdnM/IPQXocWB6fOhmwaGsLeRalxs2yQFM0zdJCwpaU9dzKsJrxepAXVuq31p r0fygWTp8GVevHXzfS7fRya8xjsTRrSs6n2kH7ErOfiep13HQypAjbyLswNe4kW/ D6x8pVC3AhdGkl/9CW4m =oUlh -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2015-05-06' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== Lots of updates for net-next for this cycle. As usual, we have a lot of small fixes and cleanups, the bigger items are: * proper mac80211 rate control locking, to fix some random crashes (this required changing other locking as well) * mac80211 "fast-xmit", a mechanism to reduce, in most cases, the amount of code we execute while going from ndo_start_xmit() to the driver * this also clears the way for properly supporting S/G and checksum and segmentation offloads ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
0e00a0f73f
@ -1353,12 +1353,7 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
|
||||
|
||||
new_flags = 0;
|
||||
|
||||
if (*total_flags & FIF_PROMISC_IN_BSS) {
|
||||
new_flags |= FIF_PROMISC_IN_BSS;
|
||||
priv->nar |= ADM8211_NAR_PR;
|
||||
priv->nar &= ~ADM8211_NAR_MM;
|
||||
mc_filter[1] = mc_filter[0] = ~0;
|
||||
} else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
|
||||
if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
|
||||
new_flags |= FIF_ALLMULTI;
|
||||
priv->nar &= ~ADM8211_NAR_PR;
|
||||
priv->nar |= ADM8211_NAR_MM;
|
||||
|
@ -447,7 +447,7 @@ struct at76_priv {
|
||||
int mac80211_registered;
|
||||
};
|
||||
|
||||
#define AT76_SUPPORTED_FILTERS FIF_PROMISC_IN_BSS
|
||||
#define AT76_SUPPORTED_FILTERS 0
|
||||
|
||||
#define SCAN_POLL_INTERVAL (HZ / 4)
|
||||
|
||||
|
@ -1319,8 +1319,7 @@ out_unlock:
|
||||
|
||||
}
|
||||
|
||||
#define AR5523_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
|
||||
FIF_ALLMULTI | \
|
||||
#define AR5523_SUPPORTED_FILTERS (FIF_ALLMULTI | \
|
||||
FIF_FCSFAIL | \
|
||||
FIF_OTHER_BSS)
|
||||
|
||||
|
@ -773,7 +773,6 @@ static int ath10k_monitor_recalc(struct ath10k *ar)
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
should_start = ar->monitor ||
|
||||
ar->filter_flags & FIF_PROMISC_IN_BSS ||
|
||||
test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC,
|
||||
@ -3493,8 +3492,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
||||
* FIXME: Has to be verified.
|
||||
*/
|
||||
#define SUPPORTED_FILTERS \
|
||||
(FIF_PROMISC_IN_BSS | \
|
||||
FIF_ALLMULTI | \
|
||||
(FIF_ALLMULTI | \
|
||||
FIF_CONTROL | \
|
||||
FIF_PSPOLL | \
|
||||
FIF_OTHER_BSS | \
|
||||
@ -5500,7 +5498,8 @@ int ath10k_mac_register(struct ath10k *ar)
|
||||
IEEE80211_HW_HAS_RATE_CONTROL |
|
||||
IEEE80211_HW_AP_LINK_PS |
|
||||
IEEE80211_HW_SPECTRUM_MGMT |
|
||||
IEEE80211_HW_SW_CRYPTO_CONTROL;
|
||||
IEEE80211_HW_SW_CRYPTO_CONTROL |
|
||||
IEEE80211_HW_SUPPORT_FAST_XMIT;
|
||||
|
||||
ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
|
||||
|
||||
|
@ -1280,7 +1280,6 @@ struct ath5k_hw {
|
||||
|
||||
DECLARE_BITMAP(status, 4);
|
||||
#define ATH_STAT_INVALID 0 /* disable hardware accesses */
|
||||
#define ATH_STAT_PROMISC 1
|
||||
#define ATH_STAT_LEDSOFT 2 /* enable LED gpio status */
|
||||
#define ATH_STAT_STARTED 3 /* opened & irqs enabled */
|
||||
#define ATH_STAT_RESET 4 /* hw reset */
|
||||
|
@ -124,7 +124,7 @@ ath5k_led_brightness_set(struct led_classdev *led_dev,
|
||||
|
||||
static int
|
||||
ath5k_register_led(struct ath5k_hw *ah, struct ath5k_led *led,
|
||||
const char *name, char *trigger)
|
||||
const char *name, const char *trigger)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
@ -369,7 +369,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
|
||||
unsigned int *new_flags, u64 multicast)
|
||||
{
|
||||
#define SUPPORTED_FIF_FLAGS \
|
||||
(FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
|
||||
(FIF_ALLMULTI | FIF_FCSFAIL | \
|
||||
FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
|
||||
FIF_BCN_PRBRESP_PROMISC)
|
||||
|
||||
@ -393,16 +393,6 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
|
||||
(AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
|
||||
AR5K_RX_FILTER_MCAST);
|
||||
|
||||
if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
|
||||
if (*new_flags & FIF_PROMISC_IN_BSS)
|
||||
__set_bit(ATH_STAT_PROMISC, ah->status);
|
||||
else
|
||||
__clear_bit(ATH_STAT_PROMISC, ah->status);
|
||||
}
|
||||
|
||||
if (test_bit(ATH_STAT_PROMISC, ah->status))
|
||||
rfilt |= AR5K_RX_FILTER_PROM;
|
||||
|
||||
/* Note, AR5K_RX_FILTER_MCAST is already enabled */
|
||||
if (*new_flags & FIF_ALLMULTI) {
|
||||
mfilt[0] = ~0;
|
||||
@ -418,8 +408,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
|
||||
if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (ah->nvifs > 1))
|
||||
rfilt |= AR5K_RX_FILTER_BEACON;
|
||||
|
||||
/* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
|
||||
* set we should only pass on control frames for this
|
||||
/* FIF_CONTROL doc says we should only pass on control frames for this
|
||||
* station. This needs testing. I believe right now this
|
||||
* enables *all* control frames, which is OK.. but
|
||||
* but we should see if we can improve on granularity */
|
||||
@ -809,7 +798,6 @@ const struct ieee80211_ops ath5k_hw_ops = {
|
||||
.sw_scan_start = ath5k_sw_scan_start,
|
||||
.sw_scan_complete = ath5k_sw_scan_complete,
|
||||
.get_stats = ath5k_get_stats,
|
||||
/* .get_tkip_seq = not implemented */
|
||||
/* .set_frag_threshold = not implemented */
|
||||
/* .set_rts_threshold = not implemented */
|
||||
/* .sta_add = not implemented */
|
||||
|
@ -1238,8 +1238,7 @@ out:
|
||||
}
|
||||
|
||||
#define SUPPORTED_FILTERS \
|
||||
(FIF_PROMISC_IN_BSS | \
|
||||
FIF_ALLMULTI | \
|
||||
(FIF_ALLMULTI | \
|
||||
FIF_CONTROL | \
|
||||
FIF_PSPOLL | \
|
||||
FIF_OTHER_BSS | \
|
||||
|
@ -872,14 +872,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
|
||||
if (priv->rxfilter & FIF_PROBE_REQ)
|
||||
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
|
||||
|
||||
/*
|
||||
* Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
|
||||
* mode interface or when in monitor mode. AP mode does not need this
|
||||
* since it receives all in-BSS frames anyway.
|
||||
*/
|
||||
if (((ah->opmode != NL80211_IFTYPE_AP) &&
|
||||
(priv->rxfilter & FIF_PROMISC_IN_BSS)) ||
|
||||
ah->is_monitoring)
|
||||
if (ah->is_monitoring)
|
||||
rfilt |= ATH9K_RX_FILTER_PROM;
|
||||
|
||||
if (priv->rxfilter & FIF_CONTROL)
|
||||
|
@ -1442,8 +1442,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
}
|
||||
|
||||
#define SUPPORTED_FILTERS \
|
||||
(FIF_PROMISC_IN_BSS | \
|
||||
FIF_ALLMULTI | \
|
||||
(FIF_ALLMULTI | \
|
||||
FIF_CONTROL | \
|
||||
FIF_PSPOLL | \
|
||||
FIF_OTHER_BSS | \
|
||||
|
@ -392,11 +392,6 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
|
||||
if (sc->cur_chan->rxfilter & FIF_PROBE_REQ)
|
||||
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
|
||||
|
||||
/*
|
||||
* Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
|
||||
* mode interface or when in monitor mode. AP mode does not need this
|
||||
* since it receives all in-BSS frames anyway.
|
||||
*/
|
||||
if (sc->sc_ah->is_monitoring)
|
||||
rfilt |= ATH9K_RX_FILTER_PROM;
|
||||
|
||||
|
@ -310,8 +310,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
|
||||
if (SUPP(CARL9170FW_RX_FILTER)) {
|
||||
ar->fw.rx_filter = true;
|
||||
ar->rx_filter_caps = FIF_FCSFAIL | FIF_PLCPFAIL |
|
||||
FIF_CONTROL | FIF_PSPOLL | FIF_OTHER_BSS |
|
||||
FIF_PROMISC_IN_BSS;
|
||||
FIF_CONTROL | FIF_PSPOLL | FIF_OTHER_BSS;
|
||||
}
|
||||
|
||||
if (SUPP(CARL9170FW_HW_COUNTERS))
|
||||
|
@ -122,7 +122,7 @@ static void carl9170_led_set_brightness(struct led_classdev *led,
|
||||
}
|
||||
|
||||
static int carl9170_led_register_led(struct ar9170 *ar, int i, char *name,
|
||||
char *trigger)
|
||||
const char *trigger)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
@ -1011,9 +1011,8 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
|
||||
if (multicast != ar->cur_mc_hash)
|
||||
WARN_ON(carl9170_update_multicast(ar, multicast));
|
||||
|
||||
if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
|
||||
ar->sniffer_enabled = !!(*new_flags &
|
||||
(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS));
|
||||
if (changed_flags & FIF_OTHER_BSS) {
|
||||
ar->sniffer_enabled = !!(*new_flags & FIF_OTHER_BSS);
|
||||
|
||||
WARN_ON(carl9170_set_operating_mode(ar));
|
||||
}
|
||||
@ -1033,7 +1032,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
|
||||
if (!(*new_flags & FIF_PSPOLL))
|
||||
rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL;
|
||||
|
||||
if (!(*new_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))) {
|
||||
if (!(*new_flags & FIF_OTHER_BSS)) {
|
||||
rx_filter |= CARL9170_RX_FILTER_OTHER_RA;
|
||||
rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL;
|
||||
}
|
||||
|
@ -3131,8 +3131,6 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
|
||||
ctl |= B43_MACCTL_KEEP_BAD;
|
||||
if (wl->filter_flags & FIF_PLCPFAIL)
|
||||
ctl |= B43_MACCTL_KEEP_BADPLCP;
|
||||
if (wl->filter_flags & FIF_PROMISC_IN_BSS)
|
||||
ctl |= B43_MACCTL_PROMISC;
|
||||
if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
|
||||
ctl |= B43_MACCTL_BEACPROMISC;
|
||||
|
||||
@ -4310,16 +4308,14 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
*fflags &= FIF_PROMISC_IN_BSS |
|
||||
FIF_ALLMULTI |
|
||||
*fflags &= FIF_ALLMULTI |
|
||||
FIF_FCSFAIL |
|
||||
FIF_PLCPFAIL |
|
||||
FIF_CONTROL |
|
||||
FIF_OTHER_BSS |
|
||||
FIF_BCN_PRBRESP_PROMISC;
|
||||
|
||||
changed &= FIF_PROMISC_IN_BSS |
|
||||
FIF_ALLMULTI |
|
||||
changed &= FIF_ALLMULTI |
|
||||
FIF_FCSFAIL |
|
||||
FIF_PLCPFAIL |
|
||||
FIF_CONTROL |
|
||||
|
@ -2055,8 +2055,6 @@ static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev)
|
||||
ctl |= B43legacy_MACCTL_KEEP_BAD;
|
||||
if (wl->filter_flags & FIF_PLCPFAIL)
|
||||
ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
|
||||
if (wl->filter_flags & FIF_PROMISC_IN_BSS)
|
||||
ctl |= B43legacy_MACCTL_PROMISC;
|
||||
if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
|
||||
ctl |= B43legacy_MACCTL_BEACPROMISC;
|
||||
|
||||
@ -2922,16 +2920,14 @@ static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&wl->irq_lock, flags);
|
||||
*fflags &= FIF_PROMISC_IN_BSS |
|
||||
FIF_ALLMULTI |
|
||||
*fflags &= FIF_ALLMULTI |
|
||||
FIF_FCSFAIL |
|
||||
FIF_PLCPFAIL |
|
||||
FIF_CONTROL |
|
||||
FIF_OTHER_BSS |
|
||||
FIF_BCN_PRBRESP_PROMISC;
|
||||
|
||||
changed &= FIF_PROMISC_IN_BSS |
|
||||
FIF_ALLMULTI |
|
||||
changed &= FIF_ALLMULTI |
|
||||
FIF_FCSFAIL |
|
||||
FIF_PLCPFAIL |
|
||||
FIF_CONTROL |
|
||||
|
@ -41,8 +41,7 @@
|
||||
#define BRCMS_FLUSH_TIMEOUT 500 /* msec */
|
||||
|
||||
/* Flags we support */
|
||||
#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
|
||||
FIF_ALLMULTI | \
|
||||
#define MAC_FILTERS (FIF_ALLMULTI | \
|
||||
FIF_FCSFAIL | \
|
||||
FIF_CONTROL | \
|
||||
FIF_OTHER_BSS | \
|
||||
@ -743,8 +742,6 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw,
|
||||
changed_flags &= MAC_FILTERS;
|
||||
*total_flags &= MAC_FILTERS;
|
||||
|
||||
if (changed_flags & FIF_PROMISC_IN_BSS)
|
||||
brcms_dbg_info(core, "FIF_PROMISC_IN_BSS\n");
|
||||
if (changed_flags & FIF_ALLMULTI)
|
||||
brcms_dbg_info(core, "FIF_ALLMULTI\n");
|
||||
if (changed_flags & FIF_FCSFAIL)
|
||||
|
@ -3571,7 +3571,7 @@ void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags)
|
||||
|
||||
wlc->filter_flags = filter_flags;
|
||||
|
||||
if (filter_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
|
||||
if (filter_flags & FIF_OTHER_BSS)
|
||||
promisc_bits |= MCTL_PROMISC;
|
||||
|
||||
if (filter_flags & FIF_BCN_PRBRESP_PROMISC)
|
||||
|
@ -578,13 +578,11 @@ void cw1200_configure_filter(struct ieee80211_hw *dev,
|
||||
{
|
||||
struct cw1200_common *priv = dev->priv;
|
||||
bool listening = !!(*total_flags &
|
||||
(FIF_PROMISC_IN_BSS |
|
||||
FIF_OTHER_BSS |
|
||||
(FIF_OTHER_BSS |
|
||||
FIF_BCN_PRBRESP_PROMISC |
|
||||
FIF_PROBE_REQ));
|
||||
|
||||
*total_flags &= FIF_PROMISC_IN_BSS |
|
||||
FIF_OTHER_BSS |
|
||||
*total_flags &= FIF_OTHER_BSS |
|
||||
FIF_FCSFAIL |
|
||||
FIF_BCN_PRBRESP_PROMISC |
|
||||
FIF_PROBE_REQ;
|
||||
@ -592,14 +590,12 @@ void cw1200_configure_filter(struct ieee80211_hw *dev,
|
||||
down(&priv->scan.lock);
|
||||
mutex_lock(&priv->conf_mutex);
|
||||
|
||||
priv->rx_filter.promiscuous = (*total_flags & FIF_PROMISC_IN_BSS)
|
||||
? 1 : 0;
|
||||
priv->rx_filter.promiscuous = 0;
|
||||
priv->rx_filter.bssid = (*total_flags & (FIF_OTHER_BSS |
|
||||
FIF_PROBE_REQ)) ? 1 : 0;
|
||||
priv->rx_filter.fcs = (*total_flags & FIF_FCSFAIL) ? 1 : 0;
|
||||
priv->disable_beacon_filter = !(*total_flags &
|
||||
(FIF_BCN_PRBRESP_PROMISC |
|
||||
FIF_PROMISC_IN_BSS |
|
||||
FIF_PROBE_REQ));
|
||||
if (priv->listening != listening) {
|
||||
priv->listening = listening;
|
||||
|
@ -3048,7 +3048,7 @@ il3945_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
|
||||
D_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", changed_flags,
|
||||
*total_flags);
|
||||
|
||||
CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
|
||||
CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
|
||||
CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);
|
||||
CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
|
||||
|
||||
@ -3074,7 +3074,7 @@ il3945_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
|
||||
* filters into the device.
|
||||
*/
|
||||
*total_flags &=
|
||||
FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
|
||||
FIF_OTHER_BSS | FIF_ALLMULTI |
|
||||
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
|
||||
}
|
||||
|
||||
|
@ -6166,7 +6166,7 @@ il4965_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
|
||||
D_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", changed_flags,
|
||||
*total_flags);
|
||||
|
||||
CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
|
||||
CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
|
||||
/* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
|
||||
CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
|
||||
CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
|
||||
@ -6192,7 +6192,7 @@ il4965_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
|
||||
* filters into the device.
|
||||
*/
|
||||
*total_flags &=
|
||||
FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
|
||||
FIF_OTHER_BSS | FIF_ALLMULTI |
|
||||
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
|
||||
}
|
||||
|
||||
|
@ -1061,7 +1061,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
|
||||
IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
|
||||
changed_flags, *total_flags);
|
||||
|
||||
CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
|
||||
CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
|
||||
/* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
|
||||
CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
|
||||
CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
|
||||
@ -1088,7 +1088,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
|
||||
* since we currently do not support programming multicast
|
||||
* filters into the device.
|
||||
*/
|
||||
*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
|
||||
*total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
|
||||
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
|
||||
}
|
||||
|
||||
@ -1140,7 +1140,6 @@ static void iwlagn_mac_event_callback(struct ieee80211_hw *hw,
|
||||
return;
|
||||
|
||||
IWL_DEBUG_MAC80211(priv, "enter\n");
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
if (priv->lib->bt_params &&
|
||||
priv->lib->bt_params->advanced_bt_coexist) {
|
||||
@ -1149,13 +1148,12 @@ static void iwlagn_mac_event_callback(struct ieee80211_hw *hw,
|
||||
else if (event->u.rssi.data == RSSI_EVENT_HIGH)
|
||||
priv->bt_enable_pspoll = false;
|
||||
|
||||
iwlagn_send_advance_bt_config(priv);
|
||||
queue_work(priv->workqueue, &priv->bt_runtime_config);
|
||||
} else {
|
||||
IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
|
||||
"ignoring RSSI callback\n");
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->mutex);
|
||||
IWL_DEBUG_MAC80211(priv, "leave\n");
|
||||
}
|
||||
|
||||
|
@ -248,7 +248,7 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
|
||||
*/
|
||||
if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
|
||||
(flags & IEEE80211_CHAN_NO_IR))
|
||||
flags |= IEEE80211_CHAN_GO_CONCURRENT;
|
||||
flags |= IEEE80211_CHAN_IR_CONCURRENT;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
@ -439,7 +439,7 @@ static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw,
|
||||
return mc_count;
|
||||
}
|
||||
|
||||
#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)
|
||||
#define SUPPORTED_FIF_FLAGS FIF_ALLMULTI
|
||||
static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
|
||||
unsigned int changed_flags,
|
||||
unsigned int *new_flags,
|
||||
@ -458,10 +458,7 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
|
||||
return;
|
||||
}
|
||||
|
||||
if (*new_flags & (FIF_PROMISC_IN_BSS))
|
||||
priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
|
||||
else
|
||||
priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
|
||||
priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
|
||||
if (*new_flags & (FIF_ALLMULTI) ||
|
||||
multicast > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
|
||||
priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
|
||||
|
@ -1554,8 +1554,6 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
|
||||
wiphy_debug(hw->wiphy, "%s\n", __func__);
|
||||
|
||||
data->rx_filter = 0;
|
||||
if (*total_flags & FIF_PROMISC_IN_BSS)
|
||||
data->rx_filter |= FIF_PROMISC_IN_BSS;
|
||||
if (*total_flags & FIF_ALLMULTI)
|
||||
data->rx_filter |= FIF_ALLMULTI;
|
||||
|
||||
@ -2399,7 +2397,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
IEEE80211_HW_WANT_MONITOR_VIF |
|
||||
IEEE80211_HW_QUEUE_CONTROL |
|
||||
IEEE80211_HW_SUPPORTS_HT_CCK_RATES |
|
||||
IEEE80211_HW_CHANCTX_STA_CSA;
|
||||
IEEE80211_HW_CHANCTX_STA_CSA |
|
||||
IEEE80211_HW_SUPPORT_FAST_XMIT;
|
||||
if (rctbl)
|
||||
hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
|
||||
|
||||
@ -2438,6 +2437,31 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz);
|
||||
sband->bitrates = data->rates + 4;
|
||||
sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
|
||||
|
||||
sband->vht_cap.vht_supported = true;
|
||||
sband->vht_cap.cap =
|
||||
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
|
||||
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
|
||||
IEEE80211_VHT_CAP_RXLDPC |
|
||||
IEEE80211_VHT_CAP_SHORT_GI_80 |
|
||||
IEEE80211_VHT_CAP_SHORT_GI_160 |
|
||||
IEEE80211_VHT_CAP_TXSTBC |
|
||||
IEEE80211_VHT_CAP_RXSTBC_1 |
|
||||
IEEE80211_VHT_CAP_RXSTBC_2 |
|
||||
IEEE80211_VHT_CAP_RXSTBC_3 |
|
||||
IEEE80211_VHT_CAP_RXSTBC_4 |
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
|
||||
sband->vht_cap.vht_mcs.rx_mcs_map =
|
||||
cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_9 << 14);
|
||||
sband->vht_cap.vht_mcs.tx_mcs_map =
|
||||
sband->vht_cap.vht_mcs.rx_mcs_map;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
@ -2458,31 +2482,6 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
|
||||
|
||||
hw->wiphy->bands[band] = sband;
|
||||
|
||||
sband->vht_cap.vht_supported = true;
|
||||
sband->vht_cap.cap =
|
||||
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
|
||||
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
|
||||
IEEE80211_VHT_CAP_RXLDPC |
|
||||
IEEE80211_VHT_CAP_SHORT_GI_80 |
|
||||
IEEE80211_VHT_CAP_SHORT_GI_160 |
|
||||
IEEE80211_VHT_CAP_TXSTBC |
|
||||
IEEE80211_VHT_CAP_RXSTBC_1 |
|
||||
IEEE80211_VHT_CAP_RXSTBC_2 |
|
||||
IEEE80211_VHT_CAP_RXSTBC_3 |
|
||||
IEEE80211_VHT_CAP_RXSTBC_4 |
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
|
||||
sband->vht_cap.vht_mcs.rx_mcs_map =
|
||||
cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
|
||||
IEEE80211_VHT_MCS_SUPPORT_0_8 << 14);
|
||||
sband->vht_cap.vht_mcs.tx_mcs_map =
|
||||
sband->vht_cap.vht_mcs.rx_mcs_map;
|
||||
}
|
||||
|
||||
/* By default all radios belong to the first group */
|
||||
|
@ -5192,7 +5192,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
|
||||
priv->sniffer_enabled = true;
|
||||
}
|
||||
|
||||
*total_flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI |
|
||||
*total_flags &= FIF_ALLMULTI |
|
||||
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL |
|
||||
FIF_OTHER_BSS;
|
||||
|
||||
|
@ -351,8 +351,7 @@ int p54_setup_mac(struct p54_common *priv)
|
||||
* "TRANSPARENT and PROMISCUOUS are mutually exclusive"
|
||||
* STSW45X0C LMAC API - page 12
|
||||
*/
|
||||
if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
|
||||
(priv->filter_flags & FIF_OTHER_BSS)) &&
|
||||
if (priv->filter_flags & FIF_OTHER_BSS &&
|
||||
(mode != P54_FILTER_TYPE_PROMISCUOUS))
|
||||
mode |= P54_FILTER_TYPE_TRANSPARENT;
|
||||
} else {
|
||||
|
@ -83,7 +83,7 @@ static void p54_led_brightness_set(struct led_classdev *led_dev,
|
||||
|
||||
static int p54_register_led(struct p54_common *priv,
|
||||
unsigned int led_index,
|
||||
char *name, char *trigger)
|
||||
char *name, const char *trigger)
|
||||
{
|
||||
struct p54_led_dev *led = &priv->leds[led_index];
|
||||
int err;
|
||||
|
@ -395,13 +395,11 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
|
||||
{
|
||||
struct p54_common *priv = dev->priv;
|
||||
|
||||
*total_flags &= FIF_PROMISC_IN_BSS |
|
||||
FIF_ALLMULTI |
|
||||
FIF_OTHER_BSS;
|
||||
*total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS;
|
||||
|
||||
priv->filter_flags = *total_flags;
|
||||
|
||||
if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
|
||||
if (changed_flags & FIF_OTHER_BSS)
|
||||
p54_setup_mac(priv);
|
||||
|
||||
if (changed_flags & FIF_ALLMULTI || multicast)
|
||||
|
@ -273,10 +273,8 @@ static void rt2400pci_config_filter(struct rt2x00_dev *rt2x00dev,
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_CONTROL,
|
||||
!(filter_flags & FIF_CONTROL));
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS));
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, 1);
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_TODS,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS) &&
|
||||
!rt2x00dev->intf_ap_count);
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1);
|
||||
rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
|
||||
|
@ -274,10 +274,8 @@ static void rt2500pci_config_filter(struct rt2x00_dev *rt2x00dev,
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_CONTROL,
|
||||
!(filter_flags & FIF_CONTROL));
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS));
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, 1);
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_TODS,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS) &&
|
||||
!rt2x00dev->intf_ap_count);
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1);
|
||||
rt2x00_set_field32(®, RXCSR0_DROP_MCAST,
|
||||
|
@ -434,10 +434,8 @@ static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev,
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL,
|
||||
!(filter_flags & FIF_CONTROL));
|
||||
rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS));
|
||||
rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, 1);
|
||||
rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS) &&
|
||||
!rt2x00dev->intf_ap_count);
|
||||
rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1);
|
||||
rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST,
|
||||
|
@ -1513,8 +1513,7 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
|
||||
!(filter_flags & FIF_FCSFAIL));
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR,
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS));
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, 1);
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1);
|
||||
rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST,
|
||||
@ -7818,21 +7817,25 @@ EXPORT_SYMBOL_GPL(rt2800_probe_hw);
|
||||
/*
|
||||
* IEEE80211 stack callback functions.
|
||||
*/
|
||||
void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
|
||||
u16 *iv16)
|
||||
void rt2800_get_key_seq(struct ieee80211_hw *hw,
|
||||
struct ieee80211_key_conf *key,
|
||||
struct ieee80211_key_seq *seq)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct mac_iveiv_entry iveiv_entry;
|
||||
u32 offset;
|
||||
|
||||
offset = MAC_IVEIV_ENTRY(hw_key_idx);
|
||||
if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
|
||||
return;
|
||||
|
||||
offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
|
||||
rt2800_register_multiread(rt2x00dev, offset,
|
||||
&iveiv_entry, sizeof(iveiv_entry));
|
||||
|
||||
memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16));
|
||||
memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32));
|
||||
memcpy(&seq->tkip.iv16, &iveiv_entry.iv[0], 2);
|
||||
memcpy(&seq->tkip.iv32, &iveiv_entry.iv[4], 4);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2800_get_tkip_seq);
|
||||
EXPORT_SYMBOL_GPL(rt2800_get_key_seq);
|
||||
|
||||
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
||||
{
|
||||
|
@ -209,8 +209,9 @@ int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
|
||||
|
||||
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev);
|
||||
|
||||
void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
|
||||
u16 *iv16);
|
||||
void rt2800_get_key_seq(struct ieee80211_hw *hw,
|
||||
struct ieee80211_key_conf *key,
|
||||
struct ieee80211_key_seq *seq);
|
||||
int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
|
||||
int rt2800_conf_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, u16 queue_idx,
|
||||
|
@ -309,7 +309,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
|
||||
.sw_scan_start = rt2x00mac_sw_scan_start,
|
||||
.sw_scan_complete = rt2x00mac_sw_scan_complete,
|
||||
.get_stats = rt2x00mac_get_stats,
|
||||
.get_tkip_seq = rt2800_get_tkip_seq,
|
||||
.get_key_seq = rt2800_get_key_seq,
|
||||
.set_rts_threshold = rt2800_set_rts_threshold,
|
||||
.sta_add = rt2x00mac_sta_add,
|
||||
.sta_remove = rt2x00mac_sta_remove,
|
||||
|
@ -148,7 +148,7 @@ static const struct ieee80211_ops rt2800soc_mac80211_ops = {
|
||||
.sw_scan_start = rt2x00mac_sw_scan_start,
|
||||
.sw_scan_complete = rt2x00mac_sw_scan_complete,
|
||||
.get_stats = rt2x00mac_get_stats,
|
||||
.get_tkip_seq = rt2800_get_tkip_seq,
|
||||
.get_key_seq = rt2800_get_key_seq,
|
||||
.set_rts_threshold = rt2800_set_rts_threshold,
|
||||
.sta_add = rt2x00mac_sta_add,
|
||||
.sta_remove = rt2x00mac_sta_remove,
|
||||
|
@ -835,7 +835,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
|
||||
.sw_scan_start = rt2x00mac_sw_scan_start,
|
||||
.sw_scan_complete = rt2x00mac_sw_scan_complete,
|
||||
.get_stats = rt2x00mac_get_stats,
|
||||
.get_tkip_seq = rt2800_get_tkip_seq,
|
||||
.get_key_seq = rt2800_get_key_seq,
|
||||
.set_rts_threshold = rt2800_set_rts_threshold,
|
||||
.sta_add = rt2x00mac_sta_add,
|
||||
.sta_remove = rt2x00mac_sta_remove,
|
||||
|
@ -359,8 +359,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
|
||||
FIF_PLCPFAIL |
|
||||
FIF_CONTROL |
|
||||
FIF_PSPOLL |
|
||||
FIF_OTHER_BSS |
|
||||
FIF_PROMISC_IN_BSS;
|
||||
FIF_OTHER_BSS;
|
||||
|
||||
/*
|
||||
* Apply some rules to the filters:
|
||||
@ -369,9 +368,6 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
|
||||
* - Multicast filter seems to kill broadcast traffic so never use it.
|
||||
*/
|
||||
*total_flags |= FIF_ALLMULTI;
|
||||
if (*total_flags & FIF_OTHER_BSS ||
|
||||
*total_flags & FIF_PROMISC_IN_BSS)
|
||||
*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
|
||||
|
||||
/*
|
||||
* If the device has a single filter for all control frames,
|
||||
|
@ -530,10 +530,8 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL,
|
||||
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS) &&
|
||||
!rt2x00dev->intf_ap_count);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST,
|
||||
|
@ -480,10 +480,8 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
|
||||
!(filter_flags & FIF_PLCPFAIL));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL,
|
||||
!(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS));
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS,
|
||||
!(filter_flags & FIF_PROMISC_IN_BSS) &&
|
||||
!rt2x00dev->intf_ap_count);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1);
|
||||
rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST,
|
||||
|
@ -27,8 +27,7 @@
|
||||
#define __RTL_CORE_H__
|
||||
|
||||
#define RTL_SUPPORTED_FILTERS \
|
||||
(FIF_PROMISC_IN_BSS | \
|
||||
FIF_ALLMULTI | FIF_CONTROL | \
|
||||
(FIF_ALLMULTI | FIF_CONTROL | \
|
||||
FIF_OTHER_BSS | \
|
||||
FIF_FCSFAIL | \
|
||||
FIF_BCN_PRBRESP_PROMISC)
|
||||
|
@ -763,8 +763,7 @@ static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw,
|
||||
return (u64)(unsigned long)fp;
|
||||
}
|
||||
|
||||
#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
|
||||
FIF_ALLMULTI | \
|
||||
#define WL1251_SUPPORTED_FILTERS (FIF_ALLMULTI | \
|
||||
FIF_FCSFAIL | \
|
||||
FIF_BCN_PRBRESP_PROMISC | \
|
||||
FIF_CONTROL | \
|
||||
@ -795,10 +794,6 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
|
||||
wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
|
||||
wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
|
||||
|
||||
if (*total & FIF_PROMISC_IN_BSS) {
|
||||
wl->rx_config |= CFG_BSSID_FILTER_EN;
|
||||
wl->rx_config |= CFG_RX_ALL_GOOD;
|
||||
}
|
||||
if (*total & FIF_ALLMULTI)
|
||||
/*
|
||||
* CFG_MC_FILTER_EN in rx_config needs to be 0 to receive
|
||||
@ -825,7 +820,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS)
|
||||
if (*total & FIF_ALLMULTI)
|
||||
ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0);
|
||||
else if (fp)
|
||||
ret = wl1251_acx_group_address_tbl(wl, fp->enabled,
|
||||
|
@ -3175,8 +3175,7 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
|
||||
return (u64)(unsigned long)fp;
|
||||
}
|
||||
|
||||
#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
|
||||
FIF_ALLMULTI | \
|
||||
#define WL1271_SUPPORTED_FILTERS (FIF_ALLMULTI | \
|
||||
FIF_FCSFAIL | \
|
||||
FIF_BCN_PRBRESP_PROMISC | \
|
||||
FIF_CONTROL | \
|
||||
@ -6077,7 +6076,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
IEEE80211_HW_AMPDU_AGGREGATION |
|
||||
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
|
||||
IEEE80211_HW_QUEUE_CONTROL |
|
||||
IEEE80211_HW_CHANCTX_STA_CSA;
|
||||
IEEE80211_HW_CHANCTX_STA_CSA |
|
||||
IEEE80211_HW_SUPPORT_FAST_XMIT;
|
||||
|
||||
wl->hw->wiphy->cipher_suites = cipher_suites;
|
||||
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
|
||||
|
@ -1230,7 +1230,7 @@ static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw,
|
||||
}
|
||||
|
||||
#define SUPPORTED_FIF_FLAGS \
|
||||
(FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
|
||||
(FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
|
||||
FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)
|
||||
static void zd_op_configure_filter(struct ieee80211_hw *hw,
|
||||
unsigned int changed_flags,
|
||||
@ -1256,7 +1256,7 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw,
|
||||
* we will have some issue with IPv6 which uses multicast for link
|
||||
* layer address resolution.
|
||||
*/
|
||||
if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI))
|
||||
if (*new_flags & FIF_ALLMULTI)
|
||||
zd_mc_add_all(&hash);
|
||||
|
||||
spin_lock_irqsave(&mac->lock, flags);
|
||||
|
@ -1516,21 +1516,12 @@ static void vnt_configure(struct ieee80211_hw *hw,
|
||||
struct vnt_private *priv = hw->priv;
|
||||
u8 rx_mode = 0;
|
||||
|
||||
*total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_PROMISC_IN_BSS |
|
||||
FIF_BCN_PRBRESP_PROMISC;
|
||||
*total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC;
|
||||
|
||||
VNSvInPortB(priv->PortOffset + MAC_REG_RCR, &rx_mode);
|
||||
|
||||
dev_dbg(&priv->pcid->dev, "rx mode in = %x\n", rx_mode);
|
||||
|
||||
if (changed_flags & FIF_PROMISC_IN_BSS) {
|
||||
/* unconditionally log net taps */
|
||||
if (*total_flags & FIF_PROMISC_IN_BSS)
|
||||
rx_mode |= RCR_UNICAST;
|
||||
else
|
||||
rx_mode &= ~RCR_UNICAST;
|
||||
}
|
||||
|
||||
if (changed_flags & FIF_ALLMULTI) {
|
||||
if (*total_flags & FIF_ALLMULTI) {
|
||||
unsigned long flags;
|
||||
|
@ -785,8 +785,7 @@ static void vnt_configure(struct ieee80211_hw *hw,
|
||||
u8 rx_mode = 0;
|
||||
int rc;
|
||||
|
||||
*total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_PROMISC_IN_BSS |
|
||||
FIF_BCN_PRBRESP_PROMISC;
|
||||
*total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC;
|
||||
|
||||
rc = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_RCR,
|
||||
MESSAGE_REQUEST_MACREG, sizeof(u8), &rx_mode);
|
||||
@ -796,14 +795,6 @@ static void vnt_configure(struct ieee80211_hw *hw,
|
||||
|
||||
dev_dbg(&priv->usb->dev, "rx mode in = %x\n", rx_mode);
|
||||
|
||||
if (changed_flags & FIF_PROMISC_IN_BSS) {
|
||||
/* unconditionally log net taps */
|
||||
if (*total_flags & FIF_PROMISC_IN_BSS)
|
||||
rx_mode |= RCR_UNICAST;
|
||||
else
|
||||
rx_mode &= ~RCR_UNICAST;
|
||||
}
|
||||
|
||||
if (changed_flags & FIF_ALLMULTI) {
|
||||
if (*total_flags & FIF_ALLMULTI) {
|
||||
if (priv->mc_list_count > 2)
|
||||
|
@ -111,7 +111,7 @@ enum ieee80211_band {
|
||||
* This may be due to the driver or due to regulatory bandwidth
|
||||
* restrictions.
|
||||
* @IEEE80211_CHAN_INDOOR_ONLY: see %NL80211_FREQUENCY_ATTR_INDOOR_ONLY
|
||||
* @IEEE80211_CHAN_GO_CONCURRENT: see %NL80211_FREQUENCY_ATTR_GO_CONCURRENT
|
||||
* @IEEE80211_CHAN_IR_CONCURRENT: see %NL80211_FREQUENCY_ATTR_IR_CONCURRENT
|
||||
* @IEEE80211_CHAN_NO_20MHZ: 20 MHz bandwidth is not permitted
|
||||
* on this channel.
|
||||
* @IEEE80211_CHAN_NO_10MHZ: 10 MHz bandwidth is not permitted
|
||||
@ -129,7 +129,7 @@ enum ieee80211_channel_flags {
|
||||
IEEE80211_CHAN_NO_80MHZ = 1<<7,
|
||||
IEEE80211_CHAN_NO_160MHZ = 1<<8,
|
||||
IEEE80211_CHAN_INDOOR_ONLY = 1<<9,
|
||||
IEEE80211_CHAN_GO_CONCURRENT = 1<<10,
|
||||
IEEE80211_CHAN_IR_CONCURRENT = 1<<10,
|
||||
IEEE80211_CHAN_NO_20MHZ = 1<<11,
|
||||
IEEE80211_CHAN_NO_10MHZ = 1<<12,
|
||||
};
|
||||
|
@ -337,10 +337,16 @@ enum ieee80211_bss_change {
|
||||
* enum ieee80211_event_type - event to be notified to the low level driver
|
||||
* @RSSI_EVENT: AP's rssi crossed the a threshold set by the driver.
|
||||
* @MLME_EVENT: event related to MLME
|
||||
* @BAR_RX_EVENT: a BAR was received
|
||||
* @BA_FRAME_TIMEOUT: Frames were released from the reordering buffer because
|
||||
* they timed out. This won't be called for each frame released, but only
|
||||
* once each time the timeout triggers.
|
||||
*/
|
||||
enum ieee80211_event_type {
|
||||
RSSI_EVENT,
|
||||
MLME_EVENT,
|
||||
BAR_RX_EVENT,
|
||||
BA_FRAME_TIMEOUT,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -354,7 +360,7 @@ enum ieee80211_rssi_event_data {
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ieee80211_rssi_event - data attached to an %RSSI_EVENT
|
||||
* struct ieee80211_rssi_event - data attached to an %RSSI_EVENT
|
||||
* @data: See &enum ieee80211_rssi_event_data
|
||||
*/
|
||||
struct ieee80211_rssi_event {
|
||||
@ -388,7 +394,7 @@ enum ieee80211_mlme_event_status {
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ieee80211_mlme_event - data attached to an %MLME_EVENT
|
||||
* struct ieee80211_mlme_event - data attached to an %MLME_EVENT
|
||||
* @data: See &enum ieee80211_mlme_event_data
|
||||
* @status: See &enum ieee80211_mlme_event_status
|
||||
* @reason: the reason code if applicable
|
||||
@ -399,17 +405,32 @@ struct ieee80211_mlme_event {
|
||||
u16 reason;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_ba_event - data attached for BlockAck related events
|
||||
* @sta: pointer to the &ieee80211_sta to which this event relates
|
||||
* @tid: the tid
|
||||
* @ssn: the starting sequence number (for %BAR_RX_EVENT)
|
||||
*/
|
||||
struct ieee80211_ba_event {
|
||||
struct ieee80211_sta *sta;
|
||||
u16 tid;
|
||||
u16 ssn;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_event - event to be sent to the driver
|
||||
* @type The event itself. See &enum ieee80211_event_type.
|
||||
* @type: The event itself. See &enum ieee80211_event_type.
|
||||
* @rssi: relevant if &type is %RSSI_EVENT
|
||||
* @mlme: relevant if &type is %AUTH_EVENT
|
||||
* @ba: relevant if &type is %BAR_RX_EVENT or %BA_FRAME_TIMEOUT
|
||||
* @u:union holding the fields above
|
||||
*/
|
||||
struct ieee80211_event {
|
||||
enum ieee80211_event_type type;
|
||||
union {
|
||||
struct ieee80211_rssi_event rssi;
|
||||
struct ieee80211_mlme_event mlme;
|
||||
struct ieee80211_ba_event ba;
|
||||
} u;
|
||||
};
|
||||
|
||||
@ -1480,6 +1501,47 @@ struct ieee80211_key_conf {
|
||||
u8 key[0];
|
||||
};
|
||||
|
||||
#define IEEE80211_MAX_PN_LEN 16
|
||||
|
||||
/**
|
||||
* struct ieee80211_key_seq - key sequence counter
|
||||
*
|
||||
* @tkip: TKIP data, containing IV32 and IV16 in host byte order
|
||||
* @ccmp: PN data, most significant byte first (big endian,
|
||||
* reverse order than in packet)
|
||||
* @aes_cmac: PN data, most significant byte first (big endian,
|
||||
* reverse order than in packet)
|
||||
* @aes_gmac: PN data, most significant byte first (big endian,
|
||||
* reverse order than in packet)
|
||||
* @gcmp: PN data, most significant byte first (big endian,
|
||||
* reverse order than in packet)
|
||||
* @hw: data for HW-only (e.g. cipher scheme) keys
|
||||
*/
|
||||
struct ieee80211_key_seq {
|
||||
union {
|
||||
struct {
|
||||
u32 iv32;
|
||||
u16 iv16;
|
||||
} tkip;
|
||||
struct {
|
||||
u8 pn[6];
|
||||
} ccmp;
|
||||
struct {
|
||||
u8 pn[6];
|
||||
} aes_cmac;
|
||||
struct {
|
||||
u8 pn[6];
|
||||
} aes_gmac;
|
||||
struct {
|
||||
u8 pn[6];
|
||||
} gcmp;
|
||||
struct {
|
||||
u8 seq[IEEE80211_MAX_PN_LEN];
|
||||
u8 seq_len;
|
||||
} hw;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_cipher_scheme - cipher scheme
|
||||
*
|
||||
@ -1795,6 +1857,10 @@ struct ieee80211_txq {
|
||||
* the driver returns 1. This also forces the driver to advertise its
|
||||
* supported cipher suites.
|
||||
*
|
||||
* @IEEE80211_HW_SUPPORT_FAST_XMIT: The driver/hardware supports fast-xmit,
|
||||
* this currently requires only the ability to calculate the duration
|
||||
* for frames.
|
||||
*
|
||||
* @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface
|
||||
* queue mapping in order to use different queues (not just one per AC)
|
||||
* for different virtual interfaces. See the doc section on HW queue
|
||||
@ -1843,7 +1909,7 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_WANT_MONITOR_VIF = 1<<14,
|
||||
IEEE80211_HW_NO_AUTO_VIF = 1<<15,
|
||||
IEEE80211_HW_SW_CRYPTO_CONTROL = 1<<16,
|
||||
/* free slots */
|
||||
IEEE80211_HW_SUPPORT_FAST_XMIT = 1<<17,
|
||||
IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18,
|
||||
IEEE80211_HW_CONNECTION_MONITOR = 1<<19,
|
||||
IEEE80211_HW_QUEUE_CONTROL = 1<<20,
|
||||
@ -1937,8 +2003,8 @@ enum ieee80211_hw_flags {
|
||||
* Use the %IEEE80211_RADIOTAP_VHT_KNOWN_* values.
|
||||
*
|
||||
* @netdev_features: netdev features to be set in each netdev created
|
||||
* from this HW. Note only HW checksum features are currently
|
||||
* compatible with mac80211. Other feature bits will be rejected.
|
||||
* from this HW. Note that not all features are usable with mac80211,
|
||||
* other features will be rejected during HW registration.
|
||||
*
|
||||
* @uapsd_queues: This bitmap is included in (re)association frame to indicate
|
||||
* for each access category if it is uAPSD trigger-enabled and delivery-
|
||||
@ -2502,10 +2568,6 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
* stack. It is always safe to pass more frames than requested,
|
||||
* but this has negative impact on power consumption.
|
||||
*
|
||||
* @FIF_PROMISC_IN_BSS: promiscuous mode within your BSS,
|
||||
* think of the BSS as your network segment and then this corresponds
|
||||
* to the regular ethernet device promiscuous mode.
|
||||
*
|
||||
* @FIF_ALLMULTI: pass all multicast frames, this is used if requested
|
||||
* by the user or if the hardware is not capable of filtering by
|
||||
* multicast address.
|
||||
@ -2522,8 +2584,8 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
* mac80211 needs to do and the amount of CPU wakeups, so you should
|
||||
* honour this flag if possible.
|
||||
*
|
||||
* @FIF_CONTROL: pass control frames (except for PS Poll), if PROMISC_IN_BSS
|
||||
* is not set then only those addressed to this station.
|
||||
* @FIF_CONTROL: pass control frames (except for PS Poll) addressed to this
|
||||
* station
|
||||
*
|
||||
* @FIF_OTHER_BSS: pass frames destined to other BSSes
|
||||
*
|
||||
@ -2533,7 +2595,6 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
* @FIF_PROBE_REQ: pass probe request frames
|
||||
*/
|
||||
enum ieee80211_filter_flags {
|
||||
FIF_PROMISC_IN_BSS = 1<<0,
|
||||
FIF_ALLMULTI = 1<<1,
|
||||
FIF_FCSFAIL = 1<<2,
|
||||
FIF_PLCPFAIL = 1<<3,
|
||||
@ -2816,9 +2877,9 @@ enum ieee80211_reconfig_type {
|
||||
* Returns zero if statistics are available.
|
||||
* The callback can sleep.
|
||||
*
|
||||
* @get_tkip_seq: If your device implements TKIP encryption in hardware this
|
||||
* callback should be provided to read the TKIP transmit IVs (both IV32
|
||||
* and IV16) for the given key from hardware.
|
||||
* @get_key_seq: If your device implements encryption in hardware and does
|
||||
* IV/PN assignment then this callback should be provided to read the
|
||||
* IV/PN for the given key from hardware.
|
||||
* The callback must be atomic.
|
||||
*
|
||||
* @set_frag_threshold: Configuration of fragmentation threshold. Assign this
|
||||
@ -3001,7 +3062,7 @@ enum ieee80211_reconfig_type {
|
||||
* The callback can sleep.
|
||||
* @event_callback: Notify driver about any event in mac80211. See
|
||||
* &enum ieee80211_event_type for the different types.
|
||||
* The callback can sleep.
|
||||
* The callback must be atomic.
|
||||
*
|
||||
* @release_buffered_frames: Release buffered frames according to the given
|
||||
* parameters. In the case where the driver buffers some frames for
|
||||
@ -3217,8 +3278,9 @@ struct ieee80211_ops {
|
||||
struct ieee80211_vif *vif);
|
||||
int (*get_stats)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_low_level_stats *stats);
|
||||
void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
|
||||
u32 *iv32, u16 *iv16);
|
||||
void (*get_key_seq)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_key_conf *key,
|
||||
struct ieee80211_key_seq *seq);
|
||||
int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
|
||||
int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
|
||||
int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
@ -3466,14 +3528,15 @@ enum ieee80211_tpt_led_trigger_flags {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
|
||||
char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
|
||||
char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw);
|
||||
char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw);
|
||||
char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
|
||||
unsigned int flags,
|
||||
const struct ieee80211_tpt_blink *blink_table,
|
||||
unsigned int blink_table_len);
|
||||
const char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
|
||||
const char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
|
||||
const char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw);
|
||||
const char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw);
|
||||
const char *
|
||||
__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
|
||||
unsigned int flags,
|
||||
const struct ieee80211_tpt_blink *blink_table,
|
||||
unsigned int blink_table_len);
|
||||
#endif
|
||||
/**
|
||||
* ieee80211_get_tx_led_name - get name of TX LED
|
||||
@ -3487,7 +3550,7 @@ char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
|
||||
*
|
||||
* Return: The name of the LED trigger. %NULL if not configured for LEDs.
|
||||
*/
|
||||
static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
|
||||
static inline const char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
return __ieee80211_get_tx_led_name(hw);
|
||||
@ -3508,7 +3571,7 @@ static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
|
||||
*
|
||||
* Return: The name of the LED trigger. %NULL if not configured for LEDs.
|
||||
*/
|
||||
static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
|
||||
static inline const char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
return __ieee80211_get_rx_led_name(hw);
|
||||
@ -3529,7 +3592,7 @@ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
|
||||
*
|
||||
* Return: The name of the LED trigger. %NULL if not configured for LEDs.
|
||||
*/
|
||||
static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
|
||||
static inline const char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
return __ieee80211_get_assoc_led_name(hw);
|
||||
@ -3550,7 +3613,7 @@ static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
|
||||
*
|
||||
* Return: The name of the LED trigger. %NULL if not configured for LEDs.
|
||||
*/
|
||||
static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
|
||||
static inline const char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
return __ieee80211_get_radio_led_name(hw);
|
||||
@ -3571,7 +3634,7 @@ static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
|
||||
*
|
||||
* Note: This function must be called before ieee80211_register_hw().
|
||||
*/
|
||||
static inline char *
|
||||
static inline const char *
|
||||
ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw, unsigned int flags,
|
||||
const struct ieee80211_tpt_blink *blink_table,
|
||||
unsigned int blink_table_len)
|
||||
@ -4251,40 +4314,6 @@ void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
|
||||
void ieee80211_aes_cmac_calculate_k1_k2(struct ieee80211_key_conf *keyconf,
|
||||
u8 *k1, u8 *k2);
|
||||
|
||||
/**
|
||||
* struct ieee80211_key_seq - key sequence counter
|
||||
*
|
||||
* @tkip: TKIP data, containing IV32 and IV16 in host byte order
|
||||
* @ccmp: PN data, most significant byte first (big endian,
|
||||
* reverse order than in packet)
|
||||
* @aes_cmac: PN data, most significant byte first (big endian,
|
||||
* reverse order than in packet)
|
||||
* @aes_gmac: PN data, most significant byte first (big endian,
|
||||
* reverse order than in packet)
|
||||
* @gcmp: PN data, most significant byte first (big endian,
|
||||
* reverse order than in packet)
|
||||
*/
|
||||
struct ieee80211_key_seq {
|
||||
union {
|
||||
struct {
|
||||
u32 iv32;
|
||||
u16 iv16;
|
||||
} tkip;
|
||||
struct {
|
||||
u8 pn[6];
|
||||
} ccmp;
|
||||
struct {
|
||||
u8 pn[6];
|
||||
} aes_cmac;
|
||||
struct {
|
||||
u8 pn[6];
|
||||
} aes_gmac;
|
||||
struct {
|
||||
u8 pn[6];
|
||||
} gcmp;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* ieee80211_get_key_tx_seq - get key TX sequence counter
|
||||
*
|
||||
|
@ -2620,16 +2620,17 @@ enum nl80211_band_attr {
|
||||
* an indoor surroundings, i.e., it is connected to AC power (and not
|
||||
* through portable DC inverters) or is under the control of a master
|
||||
* that is acting as an AP and is connected to AC power.
|
||||
* @NL80211_FREQUENCY_ATTR_GO_CONCURRENT: GO operation is allowed on this
|
||||
* @NL80211_FREQUENCY_ATTR_IR_CONCURRENT: IR operation is allowed on this
|
||||
* channel if it's connected concurrently to a BSS on the same channel on
|
||||
* the 2 GHz band or to a channel in the same UNII band (on the 5 GHz
|
||||
* band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO on a
|
||||
* channel that has the GO_CONCURRENT attribute set can be done when there
|
||||
* is a clear assessment that the device is operating under the guidance of
|
||||
* an authorized master, i.e., setting up a GO while the device is also
|
||||
* connected to an AP with DFS and radar detection on the UNII band (it is
|
||||
* up to user-space, i.e., wpa_supplicant to perform the required
|
||||
* verifications)
|
||||
* band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO or TDLS
|
||||
* off-channel on a channel that has the IR_CONCURRENT attribute set can be
|
||||
* done when there is a clear assessment that the device is operating under
|
||||
* the guidance of an authorized master, i.e., setting up a GO or TDLS
|
||||
* off-channel while the device is also connected to an AP with DFS and
|
||||
* radar detection on the UNII band (it is up to user-space, i.e.,
|
||||
* wpa_supplicant to perform the required verifications). Using this
|
||||
* attribute for IR is disallowed for master interfaces (IBSS, AP).
|
||||
* @NL80211_FREQUENCY_ATTR_NO_20MHZ: 20 MHz operation is not allowed
|
||||
* on this channel in current regulatory domain.
|
||||
* @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed
|
||||
@ -2641,7 +2642,7 @@ enum nl80211_band_attr {
|
||||
* See https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122
|
||||
* for more information on the FCC description of the relaxations allowed
|
||||
* by NL80211_FREQUENCY_ATTR_INDOOR_ONLY and
|
||||
* NL80211_FREQUENCY_ATTR_GO_CONCURRENT.
|
||||
* NL80211_FREQUENCY_ATTR_IR_CONCURRENT.
|
||||
*/
|
||||
enum nl80211_frequency_attr {
|
||||
__NL80211_FREQUENCY_ATTR_INVALID,
|
||||
@ -2659,7 +2660,7 @@ enum nl80211_frequency_attr {
|
||||
NL80211_FREQUENCY_ATTR_NO_160MHZ,
|
||||
NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
|
||||
NL80211_FREQUENCY_ATTR_INDOOR_ONLY,
|
||||
NL80211_FREQUENCY_ATTR_GO_CONCURRENT,
|
||||
NL80211_FREQUENCY_ATTR_IR_CONCURRENT,
|
||||
NL80211_FREQUENCY_ATTR_NO_20MHZ,
|
||||
NL80211_FREQUENCY_ATTR_NO_10MHZ,
|
||||
|
||||
@ -2672,6 +2673,8 @@ enum nl80211_frequency_attr {
|
||||
#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN NL80211_FREQUENCY_ATTR_NO_IR
|
||||
#define NL80211_FREQUENCY_ATTR_NO_IBSS NL80211_FREQUENCY_ATTR_NO_IR
|
||||
#define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR
|
||||
#define NL80211_FREQUENCY_ATTR_GO_CONCURRENT \
|
||||
NL80211_FREQUENCY_ATTR_IR_CONCURRENT
|
||||
|
||||
/**
|
||||
* enum nl80211_bitrate_attr - bitrate attributes
|
||||
@ -2830,7 +2833,7 @@ enum nl80211_sched_scan_match_attr {
|
||||
* @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
|
||||
* base on contiguous rules and wider channels will be allowed to cross
|
||||
* multiple contiguous/overlapping frequency ranges.
|
||||
* @NL80211_RRF_GO_CONCURRENT: See &NL80211_FREQUENCY_ATTR_GO_CONCURRENT
|
||||
* @NL80211_RRF_IR_CONCURRENT: See &NL80211_FREQUENCY_ATTR_IR_CONCURRENT
|
||||
* @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
|
||||
* @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
|
||||
* @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
|
||||
@ -2847,7 +2850,7 @@ enum nl80211_reg_rule_flags {
|
||||
NL80211_RRF_NO_IR = 1<<7,
|
||||
__NL80211_RRF_NO_IBSS = 1<<8,
|
||||
NL80211_RRF_AUTO_BW = 1<<11,
|
||||
NL80211_RRF_GO_CONCURRENT = 1<<12,
|
||||
NL80211_RRF_IR_CONCURRENT = 1<<12,
|
||||
NL80211_RRF_NO_HT40MINUS = 1<<13,
|
||||
NL80211_RRF_NO_HT40PLUS = 1<<14,
|
||||
NL80211_RRF_NO_80MHZ = 1<<15,
|
||||
@ -2859,6 +2862,7 @@ enum nl80211_reg_rule_flags {
|
||||
#define NL80211_RRF_NO_IR NL80211_RRF_NO_IR
|
||||
#define NL80211_RRF_NO_HT40 (NL80211_RRF_NO_HT40MINUS |\
|
||||
NL80211_RRF_NO_HT40PLUS)
|
||||
#define NL80211_RRF_GO_CONCURRENT NL80211_RRF_IR_CONCURRENT
|
||||
|
||||
/* For backport compatibility with older userspace */
|
||||
#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
|
||||
|
@ -302,6 +302,20 @@ config MAC80211_DEBUG_COUNTERS
|
||||
---help---
|
||||
Selecting this option causes mac80211 to keep additional
|
||||
and very verbose statistics about TX and RX handler use
|
||||
and show them in debugfs.
|
||||
as well as a few selected dot11 counters. These will be
|
||||
exposed in debugfs.
|
||||
|
||||
Note that some of the counters are not concurrency safe
|
||||
and may thus not always be accurate.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MAC80211_STA_HASH_MAX_SIZE
|
||||
int "Station hash table maximum size" if MAC80211_DEBUG_MENU
|
||||
default 0
|
||||
---help---
|
||||
Setting this option to a low value (e.g. 4) allows testing the
|
||||
hash table with collisions relatively deterministically (just
|
||||
connect more stations than the number selected here.)
|
||||
|
||||
If unsure, leave the default of 0.
|
||||
|
@ -137,6 +137,9 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy,
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
sdata->noack_map = noack_map;
|
||||
|
||||
ieee80211_check_fast_xmit_iface(sdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -309,6 +312,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u32 iv32;
|
||||
u16 iv16;
|
||||
int err = -ENOENT;
|
||||
struct ieee80211_key_seq kseq = {};
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
@ -339,10 +343,12 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
iv32 = key->u.tkip.tx.iv32;
|
||||
iv16 = key->u.tkip.tx.iv16;
|
||||
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
|
||||
drv_get_tkip_seq(sdata->local,
|
||||
key->conf.hw_key_idx,
|
||||
&iv32, &iv16);
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||
!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
|
||||
drv_get_key_seq(sdata->local, key, &kseq);
|
||||
iv32 = kseq.tkip.iv32;
|
||||
iv16 = kseq.tkip.iv16;
|
||||
}
|
||||
|
||||
seq[0] = iv16 & 0xff;
|
||||
seq[1] = (iv16 >> 8) & 0xff;
|
||||
@ -355,52 +361,85 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||
pn64 = atomic64_read(&key->u.ccmp.tx_pn);
|
||||
seq[0] = pn64;
|
||||
seq[1] = pn64 >> 8;
|
||||
seq[2] = pn64 >> 16;
|
||||
seq[3] = pn64 >> 24;
|
||||
seq[4] = pn64 >> 32;
|
||||
seq[5] = pn64 >> 40;
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||
!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
|
||||
drv_get_key_seq(sdata->local, key, &kseq);
|
||||
memcpy(seq, kseq.ccmp.pn, 6);
|
||||
} else {
|
||||
pn64 = atomic64_read(&key->u.ccmp.tx_pn);
|
||||
seq[0] = pn64;
|
||||
seq[1] = pn64 >> 8;
|
||||
seq[2] = pn64 >> 16;
|
||||
seq[3] = pn64 >> 24;
|
||||
seq[4] = pn64 >> 32;
|
||||
seq[5] = pn64 >> 40;
|
||||
}
|
||||
params.seq = seq;
|
||||
params.seq_len = 6;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
|
||||
pn64 = atomic64_read(&key->u.aes_cmac.tx_pn);
|
||||
seq[0] = pn64;
|
||||
seq[1] = pn64 >> 8;
|
||||
seq[2] = pn64 >> 16;
|
||||
seq[3] = pn64 >> 24;
|
||||
seq[4] = pn64 >> 32;
|
||||
seq[5] = pn64 >> 40;
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||
!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
|
||||
drv_get_key_seq(sdata->local, key, &kseq);
|
||||
memcpy(seq, kseq.aes_cmac.pn, 6);
|
||||
} else {
|
||||
pn64 = atomic64_read(&key->u.aes_cmac.tx_pn);
|
||||
seq[0] = pn64;
|
||||
seq[1] = pn64 >> 8;
|
||||
seq[2] = pn64 >> 16;
|
||||
seq[3] = pn64 >> 24;
|
||||
seq[4] = pn64 >> 32;
|
||||
seq[5] = pn64 >> 40;
|
||||
}
|
||||
params.seq = seq;
|
||||
params.seq_len = 6;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
||||
pn64 = atomic64_read(&key->u.aes_gmac.tx_pn);
|
||||
seq[0] = pn64;
|
||||
seq[1] = pn64 >> 8;
|
||||
seq[2] = pn64 >> 16;
|
||||
seq[3] = pn64 >> 24;
|
||||
seq[4] = pn64 >> 32;
|
||||
seq[5] = pn64 >> 40;
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||
!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
|
||||
drv_get_key_seq(sdata->local, key, &kseq);
|
||||
memcpy(seq, kseq.aes_gmac.pn, 6);
|
||||
} else {
|
||||
pn64 = atomic64_read(&key->u.aes_gmac.tx_pn);
|
||||
seq[0] = pn64;
|
||||
seq[1] = pn64 >> 8;
|
||||
seq[2] = pn64 >> 16;
|
||||
seq[3] = pn64 >> 24;
|
||||
seq[4] = pn64 >> 32;
|
||||
seq[5] = pn64 >> 40;
|
||||
}
|
||||
params.seq = seq;
|
||||
params.seq_len = 6;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
pn64 = atomic64_read(&key->u.gcmp.tx_pn);
|
||||
seq[0] = pn64;
|
||||
seq[1] = pn64 >> 8;
|
||||
seq[2] = pn64 >> 16;
|
||||
seq[3] = pn64 >> 24;
|
||||
seq[4] = pn64 >> 32;
|
||||
seq[5] = pn64 >> 40;
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||
!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
|
||||
drv_get_key_seq(sdata->local, key, &kseq);
|
||||
memcpy(seq, kseq.gcmp.pn, 6);
|
||||
} else {
|
||||
pn64 = atomic64_read(&key->u.gcmp.tx_pn);
|
||||
seq[0] = pn64;
|
||||
seq[1] = pn64 >> 8;
|
||||
seq[2] = pn64 >> 16;
|
||||
seq[3] = pn64 >> 24;
|
||||
seq[4] = pn64 >> 32;
|
||||
seq[5] = pn64 >> 40;
|
||||
}
|
||||
params.seq = seq;
|
||||
params.seq_len = 6;
|
||||
break;
|
||||
default:
|
||||
if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
|
||||
break;
|
||||
if (WARN_ON(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
|
||||
break;
|
||||
drv_get_key_seq(sdata->local, key, &kseq);
|
||||
params.seq = kseq.hw.seq;
|
||||
params.seq_len = kseq.hw.seq_len;
|
||||
break;
|
||||
}
|
||||
|
||||
params.key = key->conf.key;
|
||||
@ -2099,10 +2138,14 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
|
||||
int err;
|
||||
|
||||
if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
|
||||
ieee80211_check_fast_xmit_all(local);
|
||||
|
||||
err = drv_set_frag_threshold(local, wiphy->frag_threshold);
|
||||
|
||||
if (err)
|
||||
if (err) {
|
||||
ieee80211_check_fast_xmit_all(local);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if ((changed & WIPHY_PARAM_COVERAGE_CLASS) ||
|
||||
@ -3336,8 +3379,14 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
if (!sdata->u.mgd.associated)
|
||||
sdata_lock(sdata);
|
||||
if (!sdata->u.mgd.associated ||
|
||||
(params->offchan && params->wait &&
|
||||
local->ops->remain_on_channel &&
|
||||
memcmp(sdata->u.mgd.associated->bssid,
|
||||
mgmt->bssid, ETH_ALEN)))
|
||||
need_offchan = true;
|
||||
sdata_unlock(sdata);
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
need_offchan = true;
|
||||
|
@ -664,6 +664,8 @@ out:
|
||||
ieee80211_bss_info_change_notify(sdata,
|
||||
BSS_CHANGED_IDLE);
|
||||
|
||||
ieee80211_check_fast_xmit_iface(sdata);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1030,6 +1032,8 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
__ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
|
||||
|
||||
ieee80211_check_fast_xmit_iface(sdata);
|
||||
|
||||
if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
|
||||
ieee80211_free_chanctx(local, old_ctx);
|
||||
|
||||
@ -1376,6 +1380,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
|
||||
__ieee80211_vif_copy_chanctx_to_vlans(sdata,
|
||||
false);
|
||||
|
||||
ieee80211_check_fast_xmit_iface(sdata);
|
||||
|
||||
sdata->radar_required = sdata->reserved_radar_required;
|
||||
|
||||
if (sdata->vif.bss_conf.chandef.width !=
|
||||
|
@ -219,8 +219,8 @@ static const struct file_operations stats_ ##name## _ops = { \
|
||||
.llseek = generic_file_llseek, \
|
||||
};
|
||||
|
||||
#define DEBUGFS_STATS_ADD(name, field) \
|
||||
debugfs_create_u32(#name, 0400, statsd, (u32 *) &field);
|
||||
#define DEBUGFS_STATS_ADD(name) \
|
||||
debugfs_create_u32(#name, 0400, statsd, &local->name);
|
||||
#define DEBUGFS_DEVSTATS_ADD(name) \
|
||||
debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops);
|
||||
|
||||
@ -255,53 +255,31 @@ void debugfs_hw_add(struct ieee80211_local *local)
|
||||
if (!statsd)
|
||||
return;
|
||||
|
||||
DEBUGFS_STATS_ADD(transmitted_fragment_count,
|
||||
local->dot11TransmittedFragmentCount);
|
||||
DEBUGFS_STATS_ADD(multicast_transmitted_frame_count,
|
||||
local->dot11MulticastTransmittedFrameCount);
|
||||
DEBUGFS_STATS_ADD(failed_count, local->dot11FailedCount);
|
||||
DEBUGFS_STATS_ADD(retry_count, local->dot11RetryCount);
|
||||
DEBUGFS_STATS_ADD(multiple_retry_count,
|
||||
local->dot11MultipleRetryCount);
|
||||
DEBUGFS_STATS_ADD(frame_duplicate_count,
|
||||
local->dot11FrameDuplicateCount);
|
||||
DEBUGFS_STATS_ADD(received_fragment_count,
|
||||
local->dot11ReceivedFragmentCount);
|
||||
DEBUGFS_STATS_ADD(multicast_received_frame_count,
|
||||
local->dot11MulticastReceivedFrameCount);
|
||||
DEBUGFS_STATS_ADD(transmitted_frame_count,
|
||||
local->dot11TransmittedFrameCount);
|
||||
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_fragment,
|
||||
local->tx_handlers_drop_fragment);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_wep,
|
||||
local->tx_handlers_drop_wep);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc,
|
||||
local->tx_handlers_drop_not_assoc);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port,
|
||||
local->tx_handlers_drop_unauth_port);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_drop, local->rx_handlers_drop);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_queued, local->rx_handlers_queued);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc,
|
||||
local->rx_handlers_drop_nullfunc);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_drop_defrag,
|
||||
local->rx_handlers_drop_defrag);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_drop_short,
|
||||
local->rx_handlers_drop_short);
|
||||
DEBUGFS_STATS_ADD(tx_expand_skb_head,
|
||||
local->tx_expand_skb_head);
|
||||
DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned,
|
||||
local->tx_expand_skb_head_cloned);
|
||||
DEBUGFS_STATS_ADD(rx_expand_skb_head,
|
||||
local->rx_expand_skb_head);
|
||||
DEBUGFS_STATS_ADD(rx_expand_skb_head2,
|
||||
local->rx_expand_skb_head2);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_fragments,
|
||||
local->rx_handlers_fragments);
|
||||
DEBUGFS_STATS_ADD(tx_status_drop,
|
||||
local->tx_status_drop);
|
||||
DEBUGFS_STATS_ADD(dot11TransmittedFragmentCount);
|
||||
DEBUGFS_STATS_ADD(dot11MulticastTransmittedFrameCount);
|
||||
DEBUGFS_STATS_ADD(dot11FailedCount);
|
||||
DEBUGFS_STATS_ADD(dot11RetryCount);
|
||||
DEBUGFS_STATS_ADD(dot11MultipleRetryCount);
|
||||
DEBUGFS_STATS_ADD(dot11FrameDuplicateCount);
|
||||
DEBUGFS_STATS_ADD(dot11ReceivedFragmentCount);
|
||||
DEBUGFS_STATS_ADD(dot11MulticastReceivedFrameCount);
|
||||
DEBUGFS_STATS_ADD(dot11TransmittedFrameCount);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_queued);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_wep);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_drop);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_queued);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_drop_defrag);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_drop_short);
|
||||
DEBUGFS_STATS_ADD(tx_expand_skb_head);
|
||||
DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned);
|
||||
DEBUGFS_STATS_ADD(rx_expand_skb_head_defrag);
|
||||
DEBUGFS_STATS_ADD(rx_handlers_fragments);
|
||||
DEBUGFS_STATS_ADD(tx_status_drop);
|
||||
#endif
|
||||
DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount);
|
||||
DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
|
||||
|
@ -29,8 +29,6 @@ static ssize_t sta_ ##name## _read(struct file *file, \
|
||||
format_string, sta->field); \
|
||||
}
|
||||
#define STA_READ_D(name, field) STA_READ(name, field, "%d\n")
|
||||
#define STA_READ_U(name, field) STA_READ(name, field, "%u\n")
|
||||
#define STA_READ_S(name, field) STA_READ(name, field, "%s\n")
|
||||
|
||||
#define STA_OPS(name) \
|
||||
static const struct file_operations sta_ ##name## _ops = { \
|
||||
@ -52,10 +50,7 @@ static const struct file_operations sta_ ##name## _ops = { \
|
||||
STA_OPS(name)
|
||||
|
||||
STA_FILE(aid, sta.aid, D);
|
||||
STA_FILE(dev, sdata->name, S);
|
||||
STA_FILE(last_signal, last_signal, D);
|
||||
STA_FILE(last_ack_signal, last_ack_signal, D);
|
||||
STA_FILE(beacon_loss_count, beacon_loss_count, D);
|
||||
|
||||
static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
@ -101,40 +96,6 @@ static ssize_t sta_num_ps_buf_frames_read(struct file *file,
|
||||
}
|
||||
STA_OPS(num_ps_buf_frames);
|
||||
|
||||
static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct sta_info *sta = file->private_data;
|
||||
return mac80211_format_buffer(userbuf, count, ppos, "%d\n",
|
||||
jiffies_to_msecs(jiffies - sta->last_rx));
|
||||
}
|
||||
STA_OPS(inactive_ms);
|
||||
|
||||
|
||||
static ssize_t sta_connected_time_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct timespec uptime;
|
||||
struct tm result;
|
||||
long connected_time_secs;
|
||||
char buf[100];
|
||||
int res;
|
||||
ktime_get_ts(&uptime);
|
||||
connected_time_secs = uptime.tv_sec - sta->last_connected;
|
||||
time_to_tm(connected_time_secs, 0, &result);
|
||||
result.tm_year -= 70;
|
||||
result.tm_mday -= 1;
|
||||
res = scnprintf(buf, sizeof(buf),
|
||||
"years - %ld\nmonths - %d\ndays - %d\nclock - %d:%d:%d\n\n",
|
||||
result.tm_year, result.tm_mon, result.tm_mday,
|
||||
result.tm_hour, result.tm_min, result.tm_sec);
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
|
||||
}
|
||||
STA_OPS(connected_time);
|
||||
|
||||
|
||||
|
||||
static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
@ -359,37 +320,6 @@ static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
|
||||
}
|
||||
STA_OPS(vht_capa);
|
||||
|
||||
static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct rate_info rinfo;
|
||||
u16 rate;
|
||||
sta_set_rate_info_tx(sta, &sta->last_tx_rate, &rinfo);
|
||||
rate = cfg80211_calculate_bitrate(&rinfo);
|
||||
|
||||
return mac80211_format_buffer(userbuf, count, ppos,
|
||||
"%d.%d MBit/s\n",
|
||||
rate/10, rate%10);
|
||||
}
|
||||
STA_OPS(current_tx_rate);
|
||||
|
||||
static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct rate_info rinfo;
|
||||
u16 rate;
|
||||
|
||||
sta_set_rate_info_rx(sta, &rinfo);
|
||||
|
||||
rate = cfg80211_calculate_bitrate(&rinfo);
|
||||
|
||||
return mac80211_format_buffer(userbuf, count, ppos,
|
||||
"%d.%d MBit/s\n",
|
||||
rate/10, rate%10);
|
||||
}
|
||||
STA_OPS(last_rx_rate);
|
||||
|
||||
#define DEBUGFS_ADD(name) \
|
||||
debugfs_create_file(#name, 0400, \
|
||||
@ -432,30 +362,15 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
|
||||
|
||||
DEBUGFS_ADD(flags);
|
||||
DEBUGFS_ADD(num_ps_buf_frames);
|
||||
DEBUGFS_ADD(inactive_ms);
|
||||
DEBUGFS_ADD(connected_time);
|
||||
DEBUGFS_ADD(last_seq_ctrl);
|
||||
DEBUGFS_ADD(agg_status);
|
||||
DEBUGFS_ADD(dev);
|
||||
DEBUGFS_ADD(last_signal);
|
||||
DEBUGFS_ADD(beacon_loss_count);
|
||||
DEBUGFS_ADD(ht_capa);
|
||||
DEBUGFS_ADD(vht_capa);
|
||||
DEBUGFS_ADD(last_ack_signal);
|
||||
DEBUGFS_ADD(current_tx_rate);
|
||||
DEBUGFS_ADD(last_rx_rate);
|
||||
|
||||
DEBUGFS_ADD_COUNTER(rx_packets, rx_packets);
|
||||
DEBUGFS_ADD_COUNTER(tx_packets, tx_packets);
|
||||
DEBUGFS_ADD_COUNTER(rx_bytes, rx_bytes);
|
||||
DEBUGFS_ADD_COUNTER(tx_bytes, tx_bytes);
|
||||
DEBUGFS_ADD_COUNTER(rx_duplicates, num_duplicates);
|
||||
DEBUGFS_ADD_COUNTER(rx_fragments, rx_fragments);
|
||||
DEBUGFS_ADD_COUNTER(rx_dropped, rx_dropped);
|
||||
DEBUGFS_ADD_COUNTER(tx_fragments, tx_fragments);
|
||||
DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count);
|
||||
DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed);
|
||||
DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count);
|
||||
|
||||
if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
|
||||
debugfs_create_x32("driver_buffered_tids", 0400,
|
||||
|
@ -417,12 +417,13 @@ static inline int drv_get_stats(struct ieee80211_local *local,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void drv_get_tkip_seq(struct ieee80211_local *local,
|
||||
u8 hw_key_idx, u32 *iv32, u16 *iv16)
|
||||
static inline void drv_get_key_seq(struct ieee80211_local *local,
|
||||
struct ieee80211_key *key,
|
||||
struct ieee80211_key_seq *seq)
|
||||
{
|
||||
if (local->ops->get_tkip_seq)
|
||||
local->ops->get_tkip_seq(&local->hw, hw_key_idx, iv32, iv16);
|
||||
trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16);
|
||||
if (local->ops->get_key_seq)
|
||||
local->ops->get_key_seq(&local->hw, &key->conf, seq);
|
||||
trace_drv_get_key_seq(local, &key->conf);
|
||||
}
|
||||
|
||||
static inline int drv_set_frag_threshold(struct ieee80211_local *local,
|
||||
|
@ -38,7 +38,7 @@ static void ieee80211_get_ringparam(struct net_device *dev,
|
||||
static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
|
||||
"rx_packets", "rx_bytes",
|
||||
"rx_duplicates", "rx_fragments", "rx_dropped",
|
||||
"tx_packets", "tx_bytes", "tx_fragments",
|
||||
"tx_packets", "tx_bytes",
|
||||
"tx_filtered", "tx_retry_failed", "tx_retries",
|
||||
"beacon_loss", "sta_state", "txrate", "rxrate", "signal",
|
||||
"channel", "noise", "ch_time", "ch_time_busy",
|
||||
@ -87,7 +87,6 @@ static void ieee80211_get_stats(struct net_device *dev,
|
||||
\
|
||||
data[i++] += sinfo.tx_packets; \
|
||||
data[i++] += sinfo.tx_bytes; \
|
||||
data[i++] += sta->tx_fragments; \
|
||||
data[i++] += sta->tx_filtered_count; \
|
||||
data[i++] += sta->tx_retry_failed; \
|
||||
data[i++] += sta->tx_retry_count; \
|
||||
|
@ -181,8 +181,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
|
||||
|
||||
/**
|
||||
* enum ieee80211_packet_rx_flags - packet RX flags
|
||||
* @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed
|
||||
* (incl. multicast frames)
|
||||
* @IEEE80211_RX_FRAGMENTED: fragmented frame
|
||||
* @IEEE80211_RX_AMSDU: a-MSDU packet
|
||||
* @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed
|
||||
@ -192,7 +190,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
|
||||
* @rx_flags field of &struct ieee80211_rx_status.
|
||||
*/
|
||||
enum ieee80211_packet_rx_flags {
|
||||
IEEE80211_RX_RA_MATCH = BIT(1),
|
||||
IEEE80211_RX_FRAGMENTED = BIT(2),
|
||||
IEEE80211_RX_AMSDU = BIT(3),
|
||||
IEEE80211_RX_MALFORMED_ACTION_FRM = BIT(4),
|
||||
@ -725,7 +722,6 @@ struct ieee80211_if_mesh {
|
||||
* enum ieee80211_sub_if_data_flags - virtual interface flags
|
||||
*
|
||||
* @IEEE80211_SDATA_ALLMULTI: interface wants all multicast packets
|
||||
* @IEEE80211_SDATA_PROMISC: interface is promisc
|
||||
* @IEEE80211_SDATA_OPERATING_GMODE: operating in G-only mode
|
||||
* @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between
|
||||
* associated stations and deliver multicast frames both
|
||||
@ -735,7 +731,6 @@ struct ieee80211_if_mesh {
|
||||
*/
|
||||
enum ieee80211_sub_if_data_flags {
|
||||
IEEE80211_SDATA_ALLMULTI = BIT(0),
|
||||
IEEE80211_SDATA_PROMISC = BIT(1),
|
||||
IEEE80211_SDATA_OPERATING_GMODE = BIT(2),
|
||||
IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3),
|
||||
IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4),
|
||||
@ -1211,8 +1206,8 @@ struct ieee80211_local {
|
||||
|
||||
atomic_t agg_queue_stop[IEEE80211_MAX_QUEUES];
|
||||
|
||||
/* number of interfaces with corresponding IFF_ flags */
|
||||
atomic_t iff_allmultis, iff_promiscs;
|
||||
/* number of interfaces with allmulti RX */
|
||||
atomic_t iff_allmultis;
|
||||
|
||||
struct rate_control_ref *rate_ctrl;
|
||||
|
||||
@ -1264,6 +1259,15 @@ struct ieee80211_local {
|
||||
struct list_head chanctx_list;
|
||||
struct mutex chanctx_mtx;
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
struct led_trigger tx_led, rx_led, assoc_led, radio_led;
|
||||
struct led_trigger tpt_led;
|
||||
atomic_t tx_led_active, rx_led_active, assoc_led_active;
|
||||
atomic_t radio_led_active, tpt_led_active;
|
||||
struct tpt_led_trigger *tpt_led_trigger;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
|
||||
/* SNMP counters */
|
||||
/* dot11CountersTable */
|
||||
u32 dot11TransmittedFragmentCount;
|
||||
@ -1276,18 +1280,9 @@ struct ieee80211_local {
|
||||
u32 dot11MulticastReceivedFrameCount;
|
||||
u32 dot11TransmittedFrameCount;
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led;
|
||||
struct tpt_led_trigger *tpt_led_trigger;
|
||||
char tx_led_name[32], rx_led_name[32],
|
||||
assoc_led_name[32], radio_led_name[32];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
|
||||
/* TX/RX handler statistics */
|
||||
unsigned int tx_handlers_drop;
|
||||
unsigned int tx_handlers_queued;
|
||||
unsigned int tx_handlers_drop_fragment;
|
||||
unsigned int tx_handlers_drop_wep;
|
||||
unsigned int tx_handlers_drop_not_assoc;
|
||||
unsigned int tx_handlers_drop_unauth_port;
|
||||
@ -1298,8 +1293,7 @@ struct ieee80211_local {
|
||||
unsigned int rx_handlers_drop_short;
|
||||
unsigned int tx_expand_skb_head;
|
||||
unsigned int tx_expand_skb_head_cloned;
|
||||
unsigned int rx_expand_skb_head;
|
||||
unsigned int rx_expand_skb_head2;
|
||||
unsigned int rx_expand_skb_head_defrag;
|
||||
unsigned int rx_handlers_fragments;
|
||||
unsigned int tx_status_drop;
|
||||
#define I802_DEBUG_INC(c) (c)++
|
||||
@ -1651,6 +1645,11 @@ struct sk_buff *
|
||||
ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, u32 info_flags);
|
||||
|
||||
void ieee80211_check_fast_xmit(struct sta_info *sta);
|
||||
void ieee80211_check_fast_xmit_all(struct ieee80211_local *local);
|
||||
void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_clear_fast_xmit(struct sta_info *sta);
|
||||
|
||||
/* HT */
|
||||
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta_ht_cap *ht_cap);
|
||||
|
@ -697,9 +697,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
||||
if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
|
||||
atomic_inc(&local->iff_allmultis);
|
||||
|
||||
if (sdata->flags & IEEE80211_SDATA_PROMISC)
|
||||
atomic_inc(&local->iff_promiscs);
|
||||
|
||||
if (coming_up)
|
||||
local->open_count++;
|
||||
|
||||
@ -827,13 +824,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
|
||||
(sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1));
|
||||
|
||||
/* don't count this interface for promisc/allmulti while it is down */
|
||||
/* don't count this interface for allmulti while it is down */
|
||||
if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
|
||||
atomic_dec(&local->iff_allmultis);
|
||||
|
||||
if (sdata->flags & IEEE80211_SDATA_PROMISC)
|
||||
atomic_dec(&local->iff_promiscs);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
||||
local->fif_pspoll--;
|
||||
local->fif_probe_req--;
|
||||
@ -1047,12 +1041,10 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int allmulti, promisc, sdata_allmulti, sdata_promisc;
|
||||
int allmulti, sdata_allmulti;
|
||||
|
||||
allmulti = !!(dev->flags & IFF_ALLMULTI);
|
||||
promisc = !!(dev->flags & IFF_PROMISC);
|
||||
sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
|
||||
sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC);
|
||||
|
||||
if (allmulti != sdata_allmulti) {
|
||||
if (dev->flags & IFF_ALLMULTI)
|
||||
@ -1062,13 +1054,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
|
||||
sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
|
||||
}
|
||||
|
||||
if (promisc != sdata_promisc) {
|
||||
if (dev->flags & IFF_PROMISC)
|
||||
atomic_inc(&local->iff_promiscs);
|
||||
else
|
||||
atomic_dec(&local->iff_promiscs);
|
||||
sdata->flags ^= IEEE80211_SDATA_PROMISC;
|
||||
}
|
||||
spin_lock_bh(&local->filter_lock);
|
||||
__hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
|
||||
spin_unlock_bh(&local->filter_lock);
|
||||
@ -1109,6 +1094,35 @@ static u16 ieee80211_netdev_select_queue(struct net_device *dev,
|
||||
return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
|
||||
}
|
||||
|
||||
static struct rtnl_link_stats64 *
|
||||
ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
|
||||
{
|
||||
int i;
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
const struct pcpu_sw_netstats *tstats;
|
||||
u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
|
||||
unsigned int start;
|
||||
|
||||
tstats = per_cpu_ptr(dev->tstats, i);
|
||||
|
||||
do {
|
||||
start = u64_stats_fetch_begin_irq(&tstats->syncp);
|
||||
rx_packets = tstats->rx_packets;
|
||||
tx_packets = tstats->tx_packets;
|
||||
rx_bytes = tstats->rx_bytes;
|
||||
tx_bytes = tstats->tx_bytes;
|
||||
} while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
|
||||
|
||||
stats->rx_packets += rx_packets;
|
||||
stats->tx_packets += tx_packets;
|
||||
stats->rx_bytes += rx_bytes;
|
||||
stats->tx_bytes += tx_bytes;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
static const struct net_device_ops ieee80211_dataif_ops = {
|
||||
.ndo_open = ieee80211_open,
|
||||
.ndo_stop = ieee80211_stop,
|
||||
@ -1118,6 +1132,7 @@ static const struct net_device_ops ieee80211_dataif_ops = {
|
||||
.ndo_change_mtu = ieee80211_change_mtu,
|
||||
.ndo_set_mac_address = ieee80211_change_mac,
|
||||
.ndo_select_queue = ieee80211_netdev_select_queue,
|
||||
.ndo_get_stats64 = ieee80211_get_stats64,
|
||||
};
|
||||
|
||||
static u16 ieee80211_monitor_select_queue(struct net_device *dev,
|
||||
@ -1151,14 +1166,21 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
|
||||
.ndo_change_mtu = ieee80211_change_mtu,
|
||||
.ndo_set_mac_address = ieee80211_change_mac,
|
||||
.ndo_select_queue = ieee80211_monitor_select_queue,
|
||||
.ndo_get_stats64 = ieee80211_get_stats64,
|
||||
};
|
||||
|
||||
static void ieee80211_if_free(struct net_device *dev)
|
||||
{
|
||||
free_percpu(dev->tstats);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
static void ieee80211_if_setup(struct net_device *dev)
|
||||
{
|
||||
ether_setup(dev);
|
||||
dev->priv_flags &= ~IFF_TX_SKB_SHARING;
|
||||
dev->netdev_ops = &ieee80211_dataif_ops;
|
||||
dev->destructor = free_netdev;
|
||||
dev->destructor = ieee80211_if_free;
|
||||
}
|
||||
|
||||
static void ieee80211_iface_work(struct work_struct *work)
|
||||
@ -1699,6 +1721,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
return -ENOMEM;
|
||||
dev_net_set(ndev, wiphy_net(local->hw.wiphy));
|
||||
|
||||
ndev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
||||
if (!ndev->tstats) {
|
||||
free_netdev(ndev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ndev->needed_headroom = local->tx_headroom +
|
||||
4*6 /* four MAC addresses */
|
||||
+ 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */
|
||||
|
@ -229,6 +229,7 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (uni) {
|
||||
rcu_assign_pointer(sdata->default_unicast_key, key);
|
||||
ieee80211_check_fast_xmit_iface(sdata);
|
||||
drv_set_default_unicast_key(sdata->local, sdata, idx);
|
||||
}
|
||||
|
||||
@ -298,6 +299,7 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
||||
if (pairwise) {
|
||||
rcu_assign_pointer(sta->ptk[idx], new);
|
||||
sta->ptk_idx = idx;
|
||||
ieee80211_check_fast_xmit(sta);
|
||||
} else {
|
||||
rcu_assign_pointer(sta->gtk[idx], new);
|
||||
sta->gtk_idx = idx;
|
||||
@ -483,15 +485,17 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
|
||||
break;
|
||||
default:
|
||||
if (cs) {
|
||||
size_t len = (seq_len > MAX_PN_LEN) ?
|
||||
MAX_PN_LEN : seq_len;
|
||||
if (seq_len && seq_len != cs->pn_len) {
|
||||
kfree(key);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
key->conf.iv_len = cs->hdr_len;
|
||||
key->conf.icv_len = cs->mic_len;
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
|
||||
for (j = 0; j < len; j++)
|
||||
for (j = 0; j < seq_len; j++)
|
||||
key->u.gen.rx_pn[i][j] =
|
||||
seq[len - j - 1];
|
||||
seq[seq_len - j - 1];
|
||||
key->flags |= KEY_FLAG_CIPHER_SCHEME;
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
#define NUM_DEFAULT_KEYS 4
|
||||
#define NUM_DEFAULT_MGMT_KEYS 2
|
||||
#define MAX_PN_LEN 16
|
||||
|
||||
struct ieee80211_local;
|
||||
struct ieee80211_sub_if_data;
|
||||
@ -116,7 +115,7 @@ struct ieee80211_key {
|
||||
} gcmp;
|
||||
struct {
|
||||
/* generic cipher scheme */
|
||||
u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN];
|
||||
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_MAX_PN_LEN];
|
||||
} gen;
|
||||
} u;
|
||||
|
||||
|
@ -12,96 +12,175 @@
|
||||
#include <linux/export.h>
|
||||
#include "led.h"
|
||||
|
||||
#define MAC80211_BLINK_DELAY 50 /* ms */
|
||||
|
||||
void ieee80211_led_rx(struct ieee80211_local *local)
|
||||
{
|
||||
unsigned long led_delay = MAC80211_BLINK_DELAY;
|
||||
if (unlikely(!local->rx_led))
|
||||
return;
|
||||
led_trigger_blink_oneshot(local->rx_led, &led_delay, &led_delay, 0);
|
||||
}
|
||||
|
||||
void ieee80211_led_tx(struct ieee80211_local *local)
|
||||
{
|
||||
unsigned long led_delay = MAC80211_BLINK_DELAY;
|
||||
if (unlikely(!local->tx_led))
|
||||
return;
|
||||
led_trigger_blink_oneshot(local->tx_led, &led_delay, &led_delay, 0);
|
||||
}
|
||||
|
||||
void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
|
||||
{
|
||||
if (unlikely(!local->assoc_led))
|
||||
if (!atomic_read(&local->assoc_led_active))
|
||||
return;
|
||||
if (associated)
|
||||
led_trigger_event(local->assoc_led, LED_FULL);
|
||||
led_trigger_event(&local->assoc_led, LED_FULL);
|
||||
else
|
||||
led_trigger_event(local->assoc_led, LED_OFF);
|
||||
led_trigger_event(&local->assoc_led, LED_OFF);
|
||||
}
|
||||
|
||||
void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
|
||||
{
|
||||
if (unlikely(!local->radio_led))
|
||||
if (!atomic_read(&local->radio_led_active))
|
||||
return;
|
||||
if (enabled)
|
||||
led_trigger_event(local->radio_led, LED_FULL);
|
||||
led_trigger_event(&local->radio_led, LED_FULL);
|
||||
else
|
||||
led_trigger_event(local->radio_led, LED_OFF);
|
||||
led_trigger_event(&local->radio_led, LED_OFF);
|
||||
}
|
||||
|
||||
void ieee80211_led_names(struct ieee80211_local *local)
|
||||
void ieee80211_alloc_led_names(struct ieee80211_local *local)
|
||||
{
|
||||
snprintf(local->rx_led_name, sizeof(local->rx_led_name),
|
||||
"%srx", wiphy_name(local->hw.wiphy));
|
||||
snprintf(local->tx_led_name, sizeof(local->tx_led_name),
|
||||
"%stx", wiphy_name(local->hw.wiphy));
|
||||
snprintf(local->assoc_led_name, sizeof(local->assoc_led_name),
|
||||
"%sassoc", wiphy_name(local->hw.wiphy));
|
||||
snprintf(local->radio_led_name, sizeof(local->radio_led_name),
|
||||
"%sradio", wiphy_name(local->hw.wiphy));
|
||||
local->rx_led.name = kasprintf(GFP_KERNEL, "%srx",
|
||||
wiphy_name(local->hw.wiphy));
|
||||
local->tx_led.name = kasprintf(GFP_KERNEL, "%stx",
|
||||
wiphy_name(local->hw.wiphy));
|
||||
local->assoc_led.name = kasprintf(GFP_KERNEL, "%sassoc",
|
||||
wiphy_name(local->hw.wiphy));
|
||||
local->radio_led.name = kasprintf(GFP_KERNEL, "%sradio",
|
||||
wiphy_name(local->hw.wiphy));
|
||||
}
|
||||
|
||||
void ieee80211_free_led_names(struct ieee80211_local *local)
|
||||
{
|
||||
kfree(local->rx_led.name);
|
||||
kfree(local->tx_led.name);
|
||||
kfree(local->assoc_led.name);
|
||||
kfree(local->radio_led.name);
|
||||
}
|
||||
|
||||
static void ieee80211_tx_led_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
tx_led);
|
||||
|
||||
atomic_inc(&local->tx_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_tx_led_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
tx_led);
|
||||
|
||||
atomic_dec(&local->tx_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_led_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
rx_led);
|
||||
|
||||
atomic_inc(&local->rx_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_led_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
rx_led);
|
||||
|
||||
atomic_dec(&local->rx_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_assoc_led_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
assoc_led);
|
||||
|
||||
atomic_inc(&local->assoc_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_assoc_led_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
assoc_led);
|
||||
|
||||
atomic_dec(&local->assoc_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_radio_led_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
radio_led);
|
||||
|
||||
atomic_inc(&local->radio_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_radio_led_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
radio_led);
|
||||
|
||||
atomic_dec(&local->radio_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_tpt_led_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
tpt_led);
|
||||
|
||||
atomic_inc(&local->tpt_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_tpt_led_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
tpt_led);
|
||||
|
||||
atomic_dec(&local->tpt_led_active);
|
||||
}
|
||||
|
||||
void ieee80211_led_init(struct ieee80211_local *local)
|
||||
{
|
||||
local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
|
||||
if (local->rx_led) {
|
||||
local->rx_led->name = local->rx_led_name;
|
||||
if (led_trigger_register(local->rx_led)) {
|
||||
kfree(local->rx_led);
|
||||
local->rx_led = NULL;
|
||||
}
|
||||
atomic_set(&local->rx_led_active, 0);
|
||||
local->rx_led.activate = ieee80211_rx_led_activate;
|
||||
local->rx_led.deactivate = ieee80211_rx_led_deactivate;
|
||||
if (local->rx_led.name && led_trigger_register(&local->rx_led)) {
|
||||
kfree(local->rx_led.name);
|
||||
local->rx_led.name = NULL;
|
||||
}
|
||||
|
||||
local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
|
||||
if (local->tx_led) {
|
||||
local->tx_led->name = local->tx_led_name;
|
||||
if (led_trigger_register(local->tx_led)) {
|
||||
kfree(local->tx_led);
|
||||
local->tx_led = NULL;
|
||||
}
|
||||
atomic_set(&local->tx_led_active, 0);
|
||||
local->tx_led.activate = ieee80211_tx_led_activate;
|
||||
local->tx_led.deactivate = ieee80211_tx_led_deactivate;
|
||||
if (local->tx_led.name && led_trigger_register(&local->tx_led)) {
|
||||
kfree(local->tx_led.name);
|
||||
local->tx_led.name = NULL;
|
||||
}
|
||||
|
||||
local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
|
||||
if (local->assoc_led) {
|
||||
local->assoc_led->name = local->assoc_led_name;
|
||||
if (led_trigger_register(local->assoc_led)) {
|
||||
kfree(local->assoc_led);
|
||||
local->assoc_led = NULL;
|
||||
}
|
||||
atomic_set(&local->assoc_led_active, 0);
|
||||
local->assoc_led.activate = ieee80211_assoc_led_activate;
|
||||
local->assoc_led.deactivate = ieee80211_assoc_led_deactivate;
|
||||
if (local->assoc_led.name && led_trigger_register(&local->assoc_led)) {
|
||||
kfree(local->assoc_led.name);
|
||||
local->assoc_led.name = NULL;
|
||||
}
|
||||
|
||||
local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
|
||||
if (local->radio_led) {
|
||||
local->radio_led->name = local->radio_led_name;
|
||||
if (led_trigger_register(local->radio_led)) {
|
||||
kfree(local->radio_led);
|
||||
local->radio_led = NULL;
|
||||
}
|
||||
atomic_set(&local->radio_led_active, 0);
|
||||
local->radio_led.activate = ieee80211_radio_led_activate;
|
||||
local->radio_led.deactivate = ieee80211_radio_led_deactivate;
|
||||
if (local->radio_led.name && led_trigger_register(&local->radio_led)) {
|
||||
kfree(local->radio_led.name);
|
||||
local->radio_led.name = NULL;
|
||||
}
|
||||
|
||||
atomic_set(&local->tpt_led_active, 0);
|
||||
if (local->tpt_led_trigger) {
|
||||
if (led_trigger_register(&local->tpt_led_trigger->trig)) {
|
||||
local->tpt_led.activate = ieee80211_tpt_led_activate;
|
||||
local->tpt_led.deactivate = ieee80211_tpt_led_deactivate;
|
||||
if (led_trigger_register(&local->tpt_led)) {
|
||||
kfree(local->tpt_led_trigger);
|
||||
local->tpt_led_trigger = NULL;
|
||||
}
|
||||
@ -110,58 +189,50 @@ void ieee80211_led_init(struct ieee80211_local *local)
|
||||
|
||||
void ieee80211_led_exit(struct ieee80211_local *local)
|
||||
{
|
||||
if (local->radio_led) {
|
||||
led_trigger_unregister(local->radio_led);
|
||||
kfree(local->radio_led);
|
||||
}
|
||||
if (local->assoc_led) {
|
||||
led_trigger_unregister(local->assoc_led);
|
||||
kfree(local->assoc_led);
|
||||
}
|
||||
if (local->tx_led) {
|
||||
led_trigger_unregister(local->tx_led);
|
||||
kfree(local->tx_led);
|
||||
}
|
||||
if (local->rx_led) {
|
||||
led_trigger_unregister(local->rx_led);
|
||||
kfree(local->rx_led);
|
||||
}
|
||||
if (local->radio_led.name)
|
||||
led_trigger_unregister(&local->radio_led);
|
||||
if (local->assoc_led.name)
|
||||
led_trigger_unregister(&local->assoc_led);
|
||||
if (local->tx_led.name)
|
||||
led_trigger_unregister(&local->tx_led);
|
||||
if (local->rx_led.name)
|
||||
led_trigger_unregister(&local->rx_led);
|
||||
|
||||
if (local->tpt_led_trigger) {
|
||||
led_trigger_unregister(&local->tpt_led_trigger->trig);
|
||||
led_trigger_unregister(&local->tpt_led);
|
||||
kfree(local->tpt_led_trigger);
|
||||
}
|
||||
}
|
||||
|
||||
char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
|
||||
const char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
return local->radio_led_name;
|
||||
return local->radio_led.name;
|
||||
}
|
||||
EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
|
||||
|
||||
char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
|
||||
const char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
return local->assoc_led_name;
|
||||
return local->assoc_led.name;
|
||||
}
|
||||
EXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
|
||||
|
||||
char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
|
||||
const char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
return local->tx_led_name;
|
||||
return local->tx_led.name;
|
||||
}
|
||||
EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
|
||||
|
||||
char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
|
||||
const char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
return local->rx_led_name;
|
||||
return local->rx_led.name;
|
||||
}
|
||||
EXPORT_SYMBOL(__ieee80211_get_rx_led_name);
|
||||
|
||||
@ -211,10 +282,11 @@ static void tpt_trig_timer(unsigned long data)
|
||||
read_unlock(&tpt_trig->trig.leddev_list_lock);
|
||||
}
|
||||
|
||||
char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
|
||||
unsigned int flags,
|
||||
const struct ieee80211_tpt_blink *blink_table,
|
||||
unsigned int blink_table_len)
|
||||
const char *
|
||||
__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
|
||||
unsigned int flags,
|
||||
const struct ieee80211_tpt_blink *blink_table,
|
||||
unsigned int blink_table_len)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct tpt_led_trigger *tpt_trig;
|
||||
@ -229,7 +301,7 @@ char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
|
||||
snprintf(tpt_trig->name, sizeof(tpt_trig->name),
|
||||
"%stpt", wiphy_name(local->hw.wiphy));
|
||||
|
||||
tpt_trig->trig.name = tpt_trig->name;
|
||||
local->tpt_led.name = tpt_trig->name;
|
||||
|
||||
tpt_trig->blink_table = blink_table;
|
||||
tpt_trig->blink_table_len = blink_table_len;
|
||||
|
@ -11,25 +11,42 @@
|
||||
#include <linux/leds.h>
|
||||
#include "ieee80211_i.h"
|
||||
|
||||
#define MAC80211_BLINK_DELAY 50 /* ms */
|
||||
|
||||
static inline void ieee80211_led_rx(struct ieee80211_local *local)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
unsigned long led_delay = MAC80211_BLINK_DELAY;
|
||||
|
||||
if (!atomic_read(&local->rx_led_active))
|
||||
return;
|
||||
led_trigger_blink_oneshot(&local->rx_led, &led_delay, &led_delay, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void ieee80211_led_tx(struct ieee80211_local *local)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
unsigned long led_delay = MAC80211_BLINK_DELAY;
|
||||
|
||||
if (!atomic_read(&local->tx_led_active))
|
||||
return;
|
||||
led_trigger_blink_oneshot(&local->tx_led, &led_delay, &led_delay, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
void ieee80211_led_rx(struct ieee80211_local *local);
|
||||
void ieee80211_led_tx(struct ieee80211_local *local);
|
||||
void ieee80211_led_assoc(struct ieee80211_local *local,
|
||||
bool associated);
|
||||
void ieee80211_led_radio(struct ieee80211_local *local,
|
||||
bool enabled);
|
||||
void ieee80211_led_names(struct ieee80211_local *local);
|
||||
void ieee80211_alloc_led_names(struct ieee80211_local *local);
|
||||
void ieee80211_free_led_names(struct ieee80211_local *local);
|
||||
void ieee80211_led_init(struct ieee80211_local *local);
|
||||
void ieee80211_led_exit(struct ieee80211_local *local);
|
||||
void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
|
||||
unsigned int types_on, unsigned int types_off);
|
||||
#else
|
||||
static inline void ieee80211_led_rx(struct ieee80211_local *local)
|
||||
{
|
||||
}
|
||||
static inline void ieee80211_led_tx(struct ieee80211_local *local)
|
||||
{
|
||||
}
|
||||
static inline void ieee80211_led_assoc(struct ieee80211_local *local,
|
||||
bool associated)
|
||||
{
|
||||
@ -38,7 +55,10 @@ static inline void ieee80211_led_radio(struct ieee80211_local *local,
|
||||
bool enabled)
|
||||
{
|
||||
}
|
||||
static inline void ieee80211_led_names(struct ieee80211_local *local)
|
||||
static inline void ieee80211_alloc_led_names(struct ieee80211_local *local)
|
||||
{
|
||||
}
|
||||
static inline void ieee80211_free_led_names(struct ieee80211_local *local)
|
||||
{
|
||||
}
|
||||
static inline void ieee80211_led_init(struct ieee80211_local *local)
|
||||
@ -58,7 +78,7 @@ static inline void
|
||||
ieee80211_tpt_led_trig_tx(struct ieee80211_local *local, __le16 fc, int bytes)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
if (local->tpt_led_trigger && ieee80211_is_data(fc))
|
||||
if (ieee80211_is_data(fc) && atomic_read(&local->tpt_led_active))
|
||||
local->tpt_led_trigger->tx_bytes += bytes;
|
||||
#endif
|
||||
}
|
||||
@ -67,7 +87,7 @@ static inline void
|
||||
ieee80211_tpt_led_trig_rx(struct ieee80211_local *local, __le16 fc, int bytes)
|
||||
{
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
if (local->tpt_led_trigger && ieee80211_is_data(fc))
|
||||
if (ieee80211_is_data(fc) && atomic_read(&local->tpt_led_active))
|
||||
local->tpt_led_trigger->rx_bytes += bytes;
|
||||
#endif
|
||||
}
|
||||
|
@ -41,9 +41,6 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
|
||||
unsigned int changed_flags;
|
||||
unsigned int new_flags = 0;
|
||||
|
||||
if (atomic_read(&local->iff_promiscs))
|
||||
new_flags |= FIF_PROMISC_IN_BSS;
|
||||
|
||||
if (atomic_read(&local->iff_allmultis))
|
||||
new_flags |= FIF_ALLMULTI;
|
||||
|
||||
@ -646,7 +643,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
|
||||
skb_queue_head_init(&local->skb_queue);
|
||||
skb_queue_head_init(&local->skb_queue_unreliable);
|
||||
|
||||
ieee80211_led_names(local);
|
||||
ieee80211_alloc_led_names(local);
|
||||
|
||||
ieee80211_roc_setup(local);
|
||||
|
||||
@ -771,8 +768,11 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
|
||||
suites[w++] = WLAN_CIPHER_SUITE_BIP_GMAC_256;
|
||||
}
|
||||
|
||||
for (r = 0; r < local->hw.n_cipher_schemes; r++)
|
||||
for (r = 0; r < local->hw.n_cipher_schemes; r++) {
|
||||
suites[w++] = cs[r].cipher;
|
||||
if (WARN_ON(cs[r].pn_len > IEEE80211_MAX_PN_LEN))
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
local->hw.wiphy->cipher_suites = suites;
|
||||
@ -840,7 +840,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
|
||||
/* Only HW csum features are currently compatible with mac80211 */
|
||||
feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
|
||||
NETIF_F_HW_CSUM;
|
||||
NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA |
|
||||
NETIF_F_GSO_SOFTWARE;
|
||||
if (WARN_ON(hw->netdev_features & ~feature_whitelist))
|
||||
return -EINVAL;
|
||||
|
||||
@ -1209,6 +1210,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
|
||||
|
||||
sta_info_stop(local);
|
||||
|
||||
ieee80211_free_led_names(local);
|
||||
|
||||
wiphy_free(local->hw.wiphy);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_free_hw);
|
||||
|
@ -72,10 +72,11 @@ static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata,
|
||||
*
|
||||
* @sta: mesh peer link to restart
|
||||
*
|
||||
* Locking: this function must be called holding sta->lock
|
||||
* Locking: this function must be called holding sta->plink_lock
|
||||
*/
|
||||
static inline void mesh_plink_fsm_restart(struct sta_info *sta)
|
||||
{
|
||||
lockdep_assert_held(&sta->plink_lock);
|
||||
sta->plink_state = NL80211_PLINK_LISTEN;
|
||||
sta->llid = sta->plid = sta->reason = 0;
|
||||
sta->plink_retries = 0;
|
||||
@ -213,13 +214,15 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
|
||||
* All mesh paths with this peer as next hop will be flushed
|
||||
* Returns beacon changed flag if the beacon content changed.
|
||||
*
|
||||
* Locking: the caller must hold sta->lock
|
||||
* Locking: the caller must hold sta->plink_lock
|
||||
*/
|
||||
static u32 __mesh_plink_deactivate(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
u32 changed = 0;
|
||||
|
||||
lockdep_assert_held(&sta->plink_lock);
|
||||
|
||||
if (sta->plink_state == NL80211_PLINK_ESTAB)
|
||||
changed = mesh_plink_dec_estab_count(sdata);
|
||||
sta->plink_state = NL80211_PLINK_BLOCKED;
|
||||
@ -244,13 +247,13 @@ u32 mesh_plink_deactivate(struct sta_info *sta)
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
u32 changed;
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock_bh(&sta->plink_lock);
|
||||
changed = __mesh_plink_deactivate(sta);
|
||||
sta->reason = WLAN_REASON_MESH_PEER_CANCELED;
|
||||
mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
|
||||
sta->sta.addr, sta->llid, sta->plid,
|
||||
sta->reason);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_bh(&sta->plink_lock);
|
||||
|
||||
return changed;
|
||||
}
|
||||
@ -387,7 +390,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates);
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock_bh(&sta->plink_lock);
|
||||
sta->last_rx = jiffies;
|
||||
|
||||
/* rates and capabilities don't change during peering */
|
||||
@ -419,7 +422,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
|
||||
else
|
||||
rate_control_rate_update(local, sband, sta, changed);
|
||||
out:
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_bh(&sta->plink_lock);
|
||||
}
|
||||
|
||||
static struct sta_info *
|
||||
@ -552,7 +555,7 @@ static void mesh_plink_timer(unsigned long data)
|
||||
if (sta->sdata->local->quiescing)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock_bh(&sta->plink_lock);
|
||||
|
||||
/* If a timer fires just before a state transition on another CPU,
|
||||
* we may have already extended the timeout and changed state by the
|
||||
@ -563,7 +566,7 @@ static void mesh_plink_timer(unsigned long data)
|
||||
mpl_dbg(sta->sdata,
|
||||
"Ignoring timer for %pM in state %s (timer adjusted)",
|
||||
sta->sta.addr, mplstates[sta->plink_state]);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_bh(&sta->plink_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -573,7 +576,7 @@ static void mesh_plink_timer(unsigned long data)
|
||||
mpl_dbg(sta->sdata,
|
||||
"Ignoring timer for %pM in state %s (timer deleted)",
|
||||
sta->sta.addr, mplstates[sta->plink_state]);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_bh(&sta->plink_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -619,7 +622,7 @@ static void mesh_plink_timer(unsigned long data)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_bh(&sta->plink_lock);
|
||||
if (action)
|
||||
mesh_plink_frame_tx(sdata, action, sta->sta.addr,
|
||||
sta->llid, sta->plid, reason);
|
||||
@ -674,16 +677,16 @@ u32 mesh_plink_open(struct sta_info *sta)
|
||||
if (!test_sta_flag(sta, WLAN_STA_AUTH))
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock_bh(&sta->plink_lock);
|
||||
sta->llid = mesh_get_new_llid(sdata);
|
||||
if (sta->plink_state != NL80211_PLINK_LISTEN &&
|
||||
sta->plink_state != NL80211_PLINK_BLOCKED) {
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_bh(&sta->plink_lock);
|
||||
return 0;
|
||||
}
|
||||
sta->plink_state = NL80211_PLINK_OPN_SNT;
|
||||
mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_bh(&sta->plink_lock);
|
||||
mpl_dbg(sdata,
|
||||
"Mesh plink: starting establishment with %pM\n",
|
||||
sta->sta.addr);
|
||||
@ -700,10 +703,10 @@ u32 mesh_plink_block(struct sta_info *sta)
|
||||
{
|
||||
u32 changed;
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock_bh(&sta->plink_lock);
|
||||
changed = __mesh_plink_deactivate(sta);
|
||||
sta->plink_state = NL80211_PLINK_BLOCKED;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_bh(&sta->plink_lock);
|
||||
|
||||
return changed;
|
||||
}
|
||||
@ -758,7 +761,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
|
||||
mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr,
|
||||
mplstates[sta->plink_state], mplevents[event]);
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
spin_lock_bh(&sta->plink_lock);
|
||||
switch (sta->plink_state) {
|
||||
case NL80211_PLINK_LISTEN:
|
||||
switch (event) {
|
||||
@ -872,7 +875,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
|
||||
*/
|
||||
break;
|
||||
}
|
||||
spin_unlock_bh(&sta->lock);
|
||||
spin_unlock_bh(&sta->plink_lock);
|
||||
if (action) {
|
||||
mesh_plink_frame_tx(sdata, action, sta->sta.addr,
|
||||
sta->llid, sta->plid, sta->reason);
|
||||
|
@ -4307,15 +4307,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_bss *cbss, bool assoc)
|
||||
struct cfg80211_bss *cbss, bool assoc,
|
||||
bool override)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_bss *bss = (void *)cbss->priv;
|
||||
struct sta_info *new_sta = NULL;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_sta_ht_cap sta_ht_cap;
|
||||
bool have_sta = false, is_override = false;
|
||||
bool have_sta = false;
|
||||
int err;
|
||||
|
||||
sband = local->hw.wiphy->bands[cbss->channel->band];
|
||||
@ -4335,14 +4335,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
|
||||
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
|
||||
|
||||
is_override = (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) !=
|
||||
(sband->ht_cap.cap &
|
||||
IEEE80211_HT_CAP_SUP_WIDTH_20_40);
|
||||
|
||||
if (new_sta || is_override) {
|
||||
if (new_sta || override) {
|
||||
err = ieee80211_prep_channel(sdata, cbss);
|
||||
if (err) {
|
||||
if (new_sta)
|
||||
@ -4552,7 +4545,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
|
||||
|
||||
err = ieee80211_prep_connection(sdata, req->bss, false);
|
||||
err = ieee80211_prep_connection(sdata, req->bss, false, false);
|
||||
if (err)
|
||||
goto err_clear;
|
||||
|
||||
@ -4624,6 +4617,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_supported_band *sband;
|
||||
const u8 *ssidie, *ht_ie, *vht_ie;
|
||||
int i, err;
|
||||
bool override = false;
|
||||
|
||||
assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL);
|
||||
if (!assoc_data)
|
||||
@ -4728,14 +4722,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
|
||||
if (req->flags & ASSOC_REQ_DISABLE_HT) {
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
|
||||
}
|
||||
|
||||
if (req->flags & ASSOC_REQ_DISABLE_VHT)
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
|
||||
|
||||
/* Also disable HT if we don't support it or the AP doesn't use WMM */
|
||||
sband = local->hw.wiphy->bands[req->bss->channel->band];
|
||||
if (!sband->ht_cap.ht_supported ||
|
||||
@ -4847,7 +4833,36 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
ifmgd->dtim_period = 0;
|
||||
ifmgd->have_beacon = false;
|
||||
|
||||
err = ieee80211_prep_connection(sdata, req->bss, true);
|
||||
/* override HT/VHT configuration only if the AP and we support it */
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
|
||||
struct ieee80211_sta_ht_cap sta_ht_cap;
|
||||
|
||||
if (req->flags & ASSOC_REQ_DISABLE_HT)
|
||||
override = true;
|
||||
|
||||
memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
|
||||
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
|
||||
|
||||
/* check for 40 MHz disable override */
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ) &&
|
||||
sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
|
||||
!(sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
|
||||
override = true;
|
||||
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
|
||||
req->flags & ASSOC_REQ_DISABLE_VHT)
|
||||
override = true;
|
||||
}
|
||||
|
||||
if (req->flags & ASSOC_REQ_DISABLE_HT) {
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
|
||||
}
|
||||
|
||||
if (req->flags & ASSOC_REQ_DISABLE_VHT)
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
|
||||
|
||||
err = ieee80211_prep_connection(sdata, req->bss, true, override);
|
||||
if (err)
|
||||
goto err_clear;
|
||||
|
||||
|
@ -683,7 +683,13 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
|
||||
if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
|
||||
return;
|
||||
|
||||
ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
|
||||
if (ista) {
|
||||
spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
|
||||
spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
} else {
|
||||
ref->ops->get_rate(ref->priv, NULL, NULL, txrc);
|
||||
}
|
||||
|
||||
if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_RC_TABLE)
|
||||
return;
|
||||
|
@ -42,10 +42,12 @@ static inline void rate_control_tx_status(struct ieee80211_local *local,
|
||||
if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
if (ref->ops->tx_status)
|
||||
ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
|
||||
else
|
||||
ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
|
||||
spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -64,7 +66,9 @@ rate_control_tx_status_noskb(struct ieee80211_local *local,
|
||||
if (WARN_ON_ONCE(!ref->ops->tx_status_noskb))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
|
||||
spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
}
|
||||
|
||||
static inline void rate_control_rate_init(struct sta_info *sta)
|
||||
@ -91,8 +95,10 @@ static inline void rate_control_rate_init(struct sta_info *sta)
|
||||
|
||||
sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
|
||||
|
||||
spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
|
||||
priv_sta);
|
||||
spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
rcu_read_unlock();
|
||||
set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
|
||||
}
|
||||
@ -115,18 +121,20 @@ static inline void rate_control_rate_update(struct ieee80211_local *local,
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def,
|
||||
ista, priv_sta, changed);
|
||||
spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
|
||||
}
|
||||
|
||||
static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
|
||||
struct ieee80211_sta *sta,
|
||||
gfp_t gfp)
|
||||
struct sta_info *sta, gfp_t gfp)
|
||||
{
|
||||
return ref->ops->alloc_sta(ref->priv, sta, gfp);
|
||||
spin_lock_init(&sta->rate_ctrl_lock);
|
||||
return ref->ops->alloc_sta(ref->priv, &sta->sta, gfp);
|
||||
}
|
||||
|
||||
static inline void rate_control_free_sta(struct sta_info *sta)
|
||||
|
@ -32,6 +32,16 @@
|
||||
#include "wme.h"
|
||||
#include "rate.h"
|
||||
|
||||
static inline void ieee80211_rx_stats(struct net_device *dev, u32 len)
|
||||
{
|
||||
struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
|
||||
|
||||
u64_stats_update_begin(&tstats->syncp);
|
||||
tstats->rx_packets++;
|
||||
tstats->rx_bytes += len;
|
||||
u64_stats_update_end(&tstats->syncp);
|
||||
}
|
||||
|
||||
/*
|
||||
* monitor mode reception
|
||||
*
|
||||
@ -529,8 +539,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
||||
}
|
||||
|
||||
prev_dev = sdata->dev;
|
||||
sdata->dev->stats.rx_packets++;
|
||||
sdata->dev->stats.rx_bytes += skb->len;
|
||||
ieee80211_rx_stats(sdata->dev, skb->len);
|
||||
}
|
||||
|
||||
if (prev_dev) {
|
||||
@ -981,7 +990,6 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
|
||||
struct sk_buff *skb = rx->skb;
|
||||
struct ieee80211_local *local = rx->local;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct sta_info *sta = rx->sta;
|
||||
struct tid_ampdu_rx *tid_agg_rx;
|
||||
u16 sc;
|
||||
@ -1016,10 +1024,6 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
|
||||
ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
|
||||
goto dont_reorder;
|
||||
|
||||
/* not actually part of this BA session */
|
||||
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
||||
goto dont_reorder;
|
||||
|
||||
/* new, potentially un-ordered, ampdu frame - process it */
|
||||
|
||||
/* reset session timer */
|
||||
@ -1073,10 +1077,8 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
|
||||
if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
|
||||
rx->sta->last_seq_ctrl[rx->seqno_idx] ==
|
||||
hdr->seq_ctrl)) {
|
||||
if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
|
||||
rx->local->dot11FrameDuplicateCount++;
|
||||
rx->sta->num_duplicates++;
|
||||
}
|
||||
I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount);
|
||||
rx->sta->num_duplicates++;
|
||||
return RX_DROP_UNUSABLE;
|
||||
} else if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
|
||||
rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
|
||||
@ -1200,6 +1202,8 @@ static void sta_ps_start(struct sta_info *sta)
|
||||
ps_dbg(sdata, "STA %pM aid %d enters power save mode\n",
|
||||
sta->sta.addr, sta->sta.aid);
|
||||
|
||||
ieee80211_clear_fast_xmit(sta);
|
||||
|
||||
if (!sta->sta.txq[0])
|
||||
return;
|
||||
|
||||
@ -1265,7 +1269,7 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
int tid, ac;
|
||||
|
||||
if (!rx->sta || !(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
||||
if (!rx->sta)
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP &&
|
||||
@ -1367,11 +1371,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
|
||||
}
|
||||
}
|
||||
} else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
|
||||
u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
|
||||
NL80211_IFTYPE_OCB);
|
||||
/* OCB uses wild-card BSSID */
|
||||
if (is_broadcast_ether_addr(bssid))
|
||||
sta->last_rx = jiffies;
|
||||
sta->last_rx = jiffies;
|
||||
} else if (!is_multicast_ether_addr(hdr->addr1)) {
|
||||
/*
|
||||
* Mesh beacons will update last_rx when if they are found to
|
||||
@ -1386,9 +1386,6 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
ieee80211_sta_rx_notify(rx->sdata, hdr);
|
||||
|
||||
@ -1517,13 +1514,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
* possible.
|
||||
*/
|
||||
|
||||
/*
|
||||
* No point in finding a key and decrypting if the frame is neither
|
||||
* addressed to us nor a multicast frame.
|
||||
*/
|
||||
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
||||
return RX_CONTINUE;
|
||||
|
||||
/* start without a key */
|
||||
rx->key = NULL;
|
||||
fc = hdr->frame_control;
|
||||
@ -1795,7 +1785,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
||||
frag = sc & IEEE80211_SCTL_FRAG;
|
||||
|
||||
if (is_multicast_ether_addr(hdr->addr1)) {
|
||||
rx->local->dot11MulticastReceivedFrameCount++;
|
||||
I802_DEBUG_INC(rx->local->dot11MulticastReceivedFrameCount);
|
||||
goto out_no_led;
|
||||
}
|
||||
|
||||
@ -1878,7 +1868,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
||||
|
||||
rx->skb = __skb_dequeue(&entry->skb_list);
|
||||
if (skb_tailroom(rx->skb) < entry->extra_len) {
|
||||
I802_DEBUG_INC(rx->local->rx_expand_skb_head2);
|
||||
I802_DEBUG_INC(rx->local->rx_expand_skb_head_defrag);
|
||||
if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
|
||||
GFP_ATOMIC))) {
|
||||
I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
|
||||
@ -2054,18 +2044,15 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
|
||||
struct sk_buff *skb, *xmit_skb;
|
||||
struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
|
||||
struct sta_info *dsta;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += rx->skb->len;
|
||||
|
||||
skb = rx->skb;
|
||||
xmit_skb = NULL;
|
||||
|
||||
ieee80211_rx_stats(dev, skb->len);
|
||||
|
||||
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
|
||||
!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
|
||||
(status->rx_flags & IEEE80211_RX_RA_MATCH) &&
|
||||
(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
|
||||
if (is_multicast_ether_addr(ehdr->h_dest)) {
|
||||
/*
|
||||
@ -2206,7 +2193,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||
struct sk_buff *skb = rx->skb, *fwd_skb;
|
||||
struct ieee80211_local *local = rx->local;
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u16 q, hdrlen;
|
||||
|
||||
@ -2237,8 +2223,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||
mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr))
|
||||
return RX_DROP_MONITOR;
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control) ||
|
||||
!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (!mesh_hdr->ttl)
|
||||
@ -2329,11 +2314,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
|
||||
ieee80211_add_pending_skb(local, fwd_skb);
|
||||
out:
|
||||
if (is_multicast_ether_addr(hdr->addr1) ||
|
||||
sdata->dev->flags & IFF_PROMISC)
|
||||
if (is_multicast_ether_addr(hdr->addr1))
|
||||
return RX_CONTINUE;
|
||||
else
|
||||
return RX_DROP_MONITOR;
|
||||
return RX_DROP_MONITOR;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2444,6 +2427,9 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
|
||||
struct {
|
||||
__le16 control, start_seq_num;
|
||||
} __packed bar_data;
|
||||
struct ieee80211_event event = {
|
||||
.type = BAR_RX_EVENT,
|
||||
};
|
||||
|
||||
if (!rx->sta)
|
||||
return RX_DROP_MONITOR;
|
||||
@ -2459,6 +2445,9 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
|
||||
return RX_DROP_MONITOR;
|
||||
|
||||
start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4;
|
||||
event.u.ba.tid = tid;
|
||||
event.u.ba.ssn = start_seq_num;
|
||||
event.u.ba.sta = &rx->sta->sta;
|
||||
|
||||
/* reset session timer */
|
||||
if (tid_agg_rx->timeout)
|
||||
@ -2471,6 +2460,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
|
||||
start_seq_num, frames);
|
||||
spin_unlock(&tid_agg_rx->reorder_lock);
|
||||
|
||||
drv_event_callback(rx->local, rx->sdata, &event);
|
||||
|
||||
kfree_skb(skb);
|
||||
return RX_QUEUED;
|
||||
}
|
||||
@ -2560,9 +2551,6 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
|
||||
rx->flags |= IEEE80211_RX_BEACON_REPORTED;
|
||||
}
|
||||
|
||||
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
||||
return RX_DROP_MONITOR;
|
||||
|
||||
if (ieee80211_drop_unencrypted_mgmt(rx))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
@ -2590,9 +2578,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||
mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
switch (mgmt->u.action.category) {
|
||||
case WLAN_CATEGORY_HT:
|
||||
/* reject HT action frames from stations not supporting HT */
|
||||
@ -3076,8 +3061,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
|
||||
}
|
||||
|
||||
prev_dev = sdata->dev;
|
||||
sdata->dev->stats.rx_packets++;
|
||||
sdata->dev->stats.rx_bytes += skb->len;
|
||||
ieee80211_rx_stats(sdata->dev, skb->len);
|
||||
}
|
||||
|
||||
if (prev_dev) {
|
||||
@ -3245,16 +3229,25 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
|
||||
ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
|
||||
spin_unlock(&tid_agg_rx->reorder_lock);
|
||||
|
||||
if (!skb_queue_empty(&frames)) {
|
||||
struct ieee80211_event event = {
|
||||
.type = BA_FRAME_TIMEOUT,
|
||||
.u.ba.tid = tid,
|
||||
.u.ba.sta = &sta->sta,
|
||||
};
|
||||
drv_event_callback(rx.local, rx.sdata, &event);
|
||||
}
|
||||
|
||||
ieee80211_rx_handlers(&rx, &frames);
|
||||
}
|
||||
|
||||
/* main receive path */
|
||||
|
||||
static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||
struct ieee80211_hdr *hdr)
|
||||
static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
struct sk_buff *skb = rx->skb;
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
|
||||
int multicast = is_multicast_ether_addr(hdr->addr1);
|
||||
@ -3263,30 +3256,23 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (!bssid && !sdata->u.mgd.use_4addr)
|
||||
return false;
|
||||
if (!multicast &&
|
||||
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
|
||||
if (!(sdata->dev->flags & IFF_PROMISC) ||
|
||||
sdata->u.mgd.use_4addr)
|
||||
return false;
|
||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
}
|
||||
break;
|
||||
if (multicast)
|
||||
return true;
|
||||
return ether_addr_equal(sdata->vif.addr, hdr->addr1);
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (!bssid)
|
||||
return false;
|
||||
if (ether_addr_equal(sdata->vif.addr, hdr->addr2) ||
|
||||
ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2))
|
||||
return false;
|
||||
if (ieee80211_is_beacon(hdr->frame_control)) {
|
||||
if (ieee80211_is_beacon(hdr->frame_control))
|
||||
return true;
|
||||
} else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
|
||||
if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid))
|
||||
return false;
|
||||
} else if (!multicast &&
|
||||
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
|
||||
if (!(sdata->dev->flags & IFF_PROMISC))
|
||||
return false;
|
||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
} else if (!rx->sta) {
|
||||
if (!multicast &&
|
||||
!ether_addr_equal(sdata->vif.addr, hdr->addr1))
|
||||
return false;
|
||||
if (!rx->sta) {
|
||||
int rate_idx;
|
||||
if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
|
||||
rate_idx = 0; /* TODO: HT/VHT rates */
|
||||
@ -3295,25 +3281,18 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||
ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
|
||||
BIT(rate_idx));
|
||||
}
|
||||
break;
|
||||
return true;
|
||||
case NL80211_IFTYPE_OCB:
|
||||
if (!bssid)
|
||||
return false;
|
||||
if (ieee80211_is_beacon(hdr->frame_control)) {
|
||||
if (ieee80211_is_beacon(hdr->frame_control))
|
||||
return false;
|
||||
} else if (!is_broadcast_ether_addr(bssid)) {
|
||||
ocb_dbg(sdata, "BSSID mismatch in OCB mode!\n");
|
||||
if (!is_broadcast_ether_addr(bssid))
|
||||
return false;
|
||||
} else if (!multicast &&
|
||||
!ether_addr_equal(sdata->dev->dev_addr,
|
||||
hdr->addr1)) {
|
||||
/* if we are in promisc mode we also accept
|
||||
* packets not destined for us
|
||||
*/
|
||||
if (!(sdata->dev->flags & IFF_PROMISC))
|
||||
return false;
|
||||
rx->flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
} else if (!rx->sta) {
|
||||
if (!multicast &&
|
||||
!ether_addr_equal(sdata->dev->dev_addr, hdr->addr1))
|
||||
return false;
|
||||
if (!rx->sta) {
|
||||
int rate_idx;
|
||||
if (status->flag & RX_FLAG_HT)
|
||||
rate_idx = 0; /* TODO: HT rates */
|
||||
@ -3322,22 +3301,17 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||
ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2,
|
||||
BIT(rate_idx));
|
||||
}
|
||||
break;
|
||||
return true;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (!multicast &&
|
||||
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
|
||||
if (!(sdata->dev->flags & IFF_PROMISC))
|
||||
return false;
|
||||
|
||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
}
|
||||
break;
|
||||
if (multicast)
|
||||
return true;
|
||||
return ether_addr_equal(sdata->vif.addr, hdr->addr1);
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_AP:
|
||||
if (!bssid) {
|
||||
if (!ether_addr_equal(sdata->vif.addr, hdr->addr1))
|
||||
return false;
|
||||
} else if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) {
|
||||
if (!bssid)
|
||||
return ether_addr_equal(sdata->vif.addr, hdr->addr1);
|
||||
|
||||
if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) {
|
||||
/*
|
||||
* Accept public action frames even when the
|
||||
* BSSID doesn't match, this is used for P2P
|
||||
@ -3349,10 +3323,10 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||
return false;
|
||||
if (ieee80211_is_public_action(hdr, skb->len))
|
||||
return true;
|
||||
if (!ieee80211_is_beacon(hdr->frame_control))
|
||||
return false;
|
||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
} else if (!ieee80211_has_tods(hdr->frame_control)) {
|
||||
return ieee80211_is_beacon(hdr->frame_control);
|
||||
}
|
||||
|
||||
if (!ieee80211_has_tods(hdr->frame_control)) {
|
||||
/* ignore data frames to TDLS-peers */
|
||||
if (ieee80211_is_data(hdr->frame_control))
|
||||
return false;
|
||||
@ -3361,30 +3335,22 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||
!ether_addr_equal(bssid, hdr->addr1))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
return true;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
if (bssid || !ieee80211_is_data(hdr->frame_control))
|
||||
return false;
|
||||
if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2))
|
||||
return false;
|
||||
break;
|
||||
return ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2);
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
if (!ieee80211_is_public_action(hdr, skb->len) &&
|
||||
!ieee80211_is_probe_req(hdr->frame_control) &&
|
||||
!ieee80211_is_probe_resp(hdr->frame_control) &&
|
||||
!ieee80211_is_beacon(hdr->frame_control))
|
||||
return false;
|
||||
if (!ether_addr_equal(sdata->vif.addr, hdr->addr1) &&
|
||||
!multicast)
|
||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
break;
|
||||
return ieee80211_is_public_action(hdr, skb->len) ||
|
||||
ieee80211_is_probe_req(hdr->frame_control) ||
|
||||
ieee80211_is_probe_resp(hdr->frame_control) ||
|
||||
ieee80211_is_beacon(hdr->frame_control);
|
||||
default:
|
||||
/* should never get here */
|
||||
WARN_ON_ONCE(1);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
WARN_ON_ONCE(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3398,13 +3364,10 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
|
||||
{
|
||||
struct ieee80211_local *local = rx->local;
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
|
||||
rx->skb = skb;
|
||||
status->rx_flags |= IEEE80211_RX_RA_MATCH;
|
||||
|
||||
if (!prepare_for_handlers(rx, hdr))
|
||||
if (!ieee80211_accept_frame(rx))
|
||||
return false;
|
||||
|
||||
if (!consume) {
|
||||
@ -3447,7 +3410,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
||||
rx.local = local;
|
||||
|
||||
if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
|
||||
local->dot11ReceivedFragmentCount++;
|
||||
I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
|
||||
|
||||
if (ieee80211_is_mgmt(fc)) {
|
||||
/* drop frame if too short for header */
|
||||
|
@ -70,6 +70,7 @@ static const struct rhashtable_params sta_rht_params = {
|
||||
.key_offset = offsetof(struct sta_info, sta.addr),
|
||||
.key_len = ETH_ALEN,
|
||||
.hashfn = sta_addr_hash,
|
||||
.max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE,
|
||||
};
|
||||
|
||||
/* Caller must hold local->sta_mtx */
|
||||
@ -269,7 +270,7 @@ static int sta_prepare_rate_control(struct ieee80211_local *local,
|
||||
|
||||
sta->rate_ctrl = local->rate_ctrl;
|
||||
sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
|
||||
&sta->sta, gfp);
|
||||
sta, gfp);
|
||||
if (!sta->rate_ctrl_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -295,6 +296,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||||
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
|
||||
mutex_init(&sta->ampdu_mlme.mtx);
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
spin_lock_init(&sta->plink_lock);
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif) &&
|
||||
!sdata->u.mesh.user_mpm)
|
||||
init_timer(&sta->plink_timer);
|
||||
@ -1200,6 +1202,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||||
ps_dbg(sdata,
|
||||
"STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n",
|
||||
sta->sta.addr, sta->sta.aid, filtered, buffered);
|
||||
|
||||
ieee80211_check_fast_xmit(sta);
|
||||
}
|
||||
|
||||
static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
|
||||
@ -1598,6 +1602,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
|
||||
|
||||
if (block) {
|
||||
set_sta_flag(sta, WLAN_STA_PS_DRIVER);
|
||||
ieee80211_clear_fast_xmit(sta);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1615,6 +1620,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
|
||||
ieee80211_queue_work(hw, &sta->drv_deliver_wk);
|
||||
} else {
|
||||
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
|
||||
ieee80211_check_fast_xmit(sta);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sta_block_awake);
|
||||
@ -1719,6 +1725,7 @@ int sta_info_move_state(struct sta_info *sta,
|
||||
!sta->sdata->u.vlan.sta))
|
||||
atomic_dec(&sta->sdata->bss->num_mcast_sta);
|
||||
clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
|
||||
ieee80211_clear_fast_xmit(sta);
|
||||
}
|
||||
break;
|
||||
case IEEE80211_STA_AUTHORIZED:
|
||||
@ -1728,6 +1735,7 @@ int sta_info_move_state(struct sta_info *sta,
|
||||
!sta->sdata->u.vlan.sta))
|
||||
atomic_inc(&sta->sdata->bss->num_mcast_sta);
|
||||
set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
|
||||
ieee80211_check_fast_xmit(sta);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -241,6 +241,34 @@ struct sta_ampdu_mlme {
|
||||
/* Value to indicate no TID reservation */
|
||||
#define IEEE80211_TID_UNRESERVED 0xff
|
||||
|
||||
#define IEEE80211_FAST_XMIT_MAX_IV 18
|
||||
|
||||
/**
|
||||
* struct ieee80211_fast_tx - TX fastpath information
|
||||
* @key: key to use for hw crypto
|
||||
* @hdr: the 802.11 header to put with the frame
|
||||
* @hdr_len: actual 802.11 header length
|
||||
* @sa_offs: offset of the SA
|
||||
* @da_offs: offset of the DA
|
||||
* @pn_offs: offset where to put PN for crypto (or 0 if not needed)
|
||||
* @band: band this will be transmitted on, for tx_info
|
||||
* @rcu_head: RCU head to free this struct
|
||||
*
|
||||
* This struct is small enough so that the common case (maximum crypto
|
||||
* header length of 8 like for CCMP/GCMP) fits into a single 64-byte
|
||||
* cache line.
|
||||
*/
|
||||
struct ieee80211_fast_tx {
|
||||
struct ieee80211_key *key;
|
||||
u8 hdr_len;
|
||||
u8 sa_offs, da_offs, pn_offs;
|
||||
u8 band;
|
||||
u8 hdr[30 + 2 + IEEE80211_FAST_XMIT_MAX_IV +
|
||||
sizeof(rfc1042_header)];
|
||||
|
||||
struct rcu_head rcu_head;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sta_info - STA information
|
||||
*
|
||||
@ -257,6 +285,8 @@ struct sta_ampdu_mlme {
|
||||
* @gtk: group keys negotiated with this station, if any
|
||||
* @gtk_idx: last installed group key index
|
||||
* @rate_ctrl: rate control algorithm reference
|
||||
* @rate_ctrl_lock: spinlock used to protect rate control data
|
||||
* (data inside the algorithm, so serializes calls there)
|
||||
* @rate_ctrl_priv: rate control private per-STA pointer
|
||||
* @last_tx_rate: rate used for last transmit, to report to userspace as
|
||||
* "the" transmit rate
|
||||
@ -295,10 +325,10 @@ struct sta_ampdu_mlme {
|
||||
* @fail_avg: moving percentage of failed MSDUs
|
||||
* @tx_packets: number of RX/TX MSDUs
|
||||
* @tx_bytes: number of bytes transmitted to this STA
|
||||
* @tx_fragments: number of transmitted MPDUs
|
||||
* @tid_seq: per-TID sequence numbers for sending to this STA
|
||||
* @ampdu_mlme: A-MPDU state machine state
|
||||
* @timer_to_tid: identity mapping to ID timers
|
||||
* @plink_lock: serialize access to plink fields
|
||||
* @llid: Local link ID
|
||||
* @plid: Peer link ID
|
||||
* @reason: Cancel reason on PLINK_HOLDING state
|
||||
@ -338,6 +368,7 @@ struct sta_ampdu_mlme {
|
||||
* using IEEE80211_NUM_TID entry for non-QoS frames
|
||||
* @rx_msdu: MSDUs received from this station, using IEEE80211_NUM_TID
|
||||
* entry for non-QoS frames
|
||||
* @fast_tx: TX fastpath information
|
||||
*/
|
||||
struct sta_info {
|
||||
/* General information, mostly static */
|
||||
@ -352,8 +383,11 @@ struct sta_info {
|
||||
u8 ptk_idx;
|
||||
struct rate_control_ref *rate_ctrl;
|
||||
void *rate_ctrl_priv;
|
||||
spinlock_t rate_ctrl_lock;
|
||||
spinlock_t lock;
|
||||
|
||||
struct ieee80211_fast_tx __rcu *fast_tx;
|
||||
|
||||
struct work_struct drv_deliver_wk;
|
||||
|
||||
u16 listen_interval;
|
||||
@ -400,7 +434,6 @@ struct sta_info {
|
||||
unsigned int fail_avg;
|
||||
|
||||
/* Updated from TX path only, no locking requirements */
|
||||
u32 tx_fragments;
|
||||
u64 tx_packets[IEEE80211_NUM_ACS];
|
||||
u64 tx_bytes[IEEE80211_NUM_ACS];
|
||||
struct ieee80211_tx_rate last_tx_rate;
|
||||
@ -422,9 +455,10 @@ struct sta_info {
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
/*
|
||||
* Mesh peer link attributes
|
||||
* Mesh peer link attributes, protected by plink_lock.
|
||||
* TODO: move to a sub-structure that is referenced with pointer?
|
||||
*/
|
||||
spinlock_t plink_lock;
|
||||
u16 llid;
|
||||
u16 plid;
|
||||
u16 reason;
|
||||
@ -432,6 +466,7 @@ struct sta_info {
|
||||
enum nl80211_plink_state plink_state;
|
||||
u32 plink_timeout;
|
||||
struct timer_list plink_timer;
|
||||
|
||||
s64 t_offset;
|
||||
s64 t_offset_setpoint;
|
||||
/* mesh power save */
|
||||
|
@ -631,15 +631,15 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
|
||||
}
|
||||
|
||||
if (acked || noack_success) {
|
||||
local->dot11TransmittedFrameCount++;
|
||||
if (!pubsta)
|
||||
local->dot11MulticastTransmittedFrameCount++;
|
||||
if (retry_count > 0)
|
||||
local->dot11RetryCount++;
|
||||
if (retry_count > 1)
|
||||
local->dot11MultipleRetryCount++;
|
||||
I802_DEBUG_INC(local->dot11TransmittedFrameCount);
|
||||
if (!pubsta)
|
||||
I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
|
||||
if (retry_count > 0)
|
||||
I802_DEBUG_INC(local->dot11RetryCount);
|
||||
if (retry_count > 1)
|
||||
I802_DEBUG_INC(local->dot11MultipleRetryCount);
|
||||
} else {
|
||||
local->dot11FailedCount++;
|
||||
I802_DEBUG_INC(local->dot11FailedCount);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_tx_status_noskb);
|
||||
@ -802,13 +802,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
if ((info->flags & IEEE80211_TX_STAT_ACK) ||
|
||||
(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED)) {
|
||||
if (ieee80211_is_first_frag(hdr->seq_ctrl)) {
|
||||
local->dot11TransmittedFrameCount++;
|
||||
I802_DEBUG_INC(local->dot11TransmittedFrameCount);
|
||||
if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
|
||||
local->dot11MulticastTransmittedFrameCount++;
|
||||
I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
|
||||
if (retry_count > 0)
|
||||
local->dot11RetryCount++;
|
||||
I802_DEBUG_INC(local->dot11RetryCount);
|
||||
if (retry_count > 1)
|
||||
local->dot11MultipleRetryCount++;
|
||||
I802_DEBUG_INC(local->dot11MultipleRetryCount);
|
||||
}
|
||||
|
||||
/* This counter shall be incremented for an acknowledged MPDU
|
||||
@ -818,10 +818,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
if (!is_multicast_ether_addr(hdr->addr1) ||
|
||||
ieee80211_is_data(fc) ||
|
||||
ieee80211_is_mgmt(fc))
|
||||
local->dot11TransmittedFragmentCount++;
|
||||
I802_DEBUG_INC(local->dot11TransmittedFragmentCount);
|
||||
} else {
|
||||
if (ieee80211_is_first_frag(hdr->seq_ctrl))
|
||||
local->dot11FailedCount++;
|
||||
I802_DEBUG_INC(local->dot11FailedCount);
|
||||
}
|
||||
|
||||
if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) &&
|
||||
|
@ -69,6 +69,17 @@
|
||||
#define CHANCTX_PR_ARG CHANDEF_PR_ARG, MIN_CHANDEF_PR_ARG, \
|
||||
__entry->rx_chains_static, __entry->rx_chains_dynamic
|
||||
|
||||
#define KEY_ENTRY __field(u32, cipher) \
|
||||
__field(u8, hw_key_idx) \
|
||||
__field(u8, flags) \
|
||||
__field(s8, keyidx)
|
||||
#define KEY_ASSIGN(k) __entry->cipher = (k)->cipher; \
|
||||
__entry->flags = (k)->flags; \
|
||||
__entry->keyidx = (k)->keyidx; \
|
||||
__entry->hw_key_idx = (k)->hw_key_idx;
|
||||
#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
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@ -522,25 +533,19 @@ TRACE_EVENT(drv_set_key,
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
STA_ENTRY
|
||||
__field(u32, cipher)
|
||||
__field(u8, hw_key_idx)
|
||||
__field(u8, flags)
|
||||
__field(s8, keyidx)
|
||||
KEY_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
STA_ASSIGN;
|
||||
__entry->cipher = key->cipher;
|
||||
__entry->flags = key->flags;
|
||||
__entry->keyidx = key->keyidx;
|
||||
__entry->hw_key_idx = key->hw_key_idx;
|
||||
KEY_ASSIGN(key);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT,
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
|
||||
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT KEY_PR_FMT,
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, KEY_PR_ARG
|
||||
)
|
||||
);
|
||||
|
||||
@ -656,28 +661,25 @@ TRACE_EVENT(drv_get_stats,
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_get_tkip_seq,
|
||||
TRACE_EVENT(drv_get_key_seq,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
u8 hw_key_idx, u32 *iv32, u16 *iv16),
|
||||
struct ieee80211_key_conf *key),
|
||||
|
||||
TP_ARGS(local, hw_key_idx, iv32, iv16),
|
||||
TP_ARGS(local, key),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
__field(u8, hw_key_idx)
|
||||
__field(u32, iv32)
|
||||
__field(u16, iv16)
|
||||
KEY_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
__entry->hw_key_idx = hw_key_idx;
|
||||
__entry->iv32 = *iv32;
|
||||
__entry->iv16 = *iv16;
|
||||
KEY_ASSIGN(key);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT, LOCAL_PR_ARG
|
||||
LOCAL_PR_FMT KEY_PR_FMT,
|
||||
LOCAL_PR_ARG, KEY_PR_ARG
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -37,6 +37,16 @@
|
||||
|
||||
/* misc utils */
|
||||
|
||||
static inline void ieee80211_tx_stats(struct net_device *dev, u32 len)
|
||||
{
|
||||
struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
|
||||
|
||||
u64_stats_update_begin(&tstats->syncp);
|
||||
tstats->tx_packets++;
|
||||
tstats->tx_bytes += len;
|
||||
u64_stats_update_end(&tstats->syncp);
|
||||
}
|
||||
|
||||
static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
|
||||
struct sk_buff *skb, int group_addr,
|
||||
int next_frag_len)
|
||||
@ -987,7 +997,6 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
|
||||
|
||||
skb_queue_walk(&tx->skbs, skb) {
|
||||
ac = skb_get_queue_mapping(skb);
|
||||
tx->sta->tx_fragments++;
|
||||
tx->sta->tx_bytes[ac] += skb->len;
|
||||
}
|
||||
if (ac >= 0)
|
||||
@ -1600,7 +1609,7 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
|
||||
if (skb_cloned(skb) &&
|
||||
(!(local->hw.flags & IEEE80211_HW_SUPPORTS_CLONED_SKBS) ||
|
||||
!skb_clone_writable(skb, ETH_HLEN) ||
|
||||
sdata->crypto_tx_tailroom_needed_cnt))
|
||||
(may_encrypt && sdata->crypto_tx_tailroom_needed_cnt)))
|
||||
I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
|
||||
else if (head_need || tail_need)
|
||||
I802_DEBUG_INC(local->tx_expand_skb_head);
|
||||
@ -2387,12 +2396,460 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* fast-xmit overview
|
||||
*
|
||||
* The core idea of this fast-xmit is to remove per-packet checks by checking
|
||||
* them out of band. ieee80211_check_fast_xmit() implements the out-of-band
|
||||
* checks that are needed to get the sta->fast_tx pointer assigned, after which
|
||||
* much less work can be done per packet. For example, fragmentation must be
|
||||
* disabled or the fast_tx pointer will not be set. All the conditions are seen
|
||||
* in the code here.
|
||||
*
|
||||
* Once assigned, the fast_tx data structure also caches the per-packet 802.11
|
||||
* header and other data to aid packet processing in ieee80211_xmit_fast().
|
||||
*
|
||||
* The most difficult part of this is that when any of these assumptions
|
||||
* change, an external trigger (i.e. a call to ieee80211_clear_fast_xmit(),
|
||||
* ieee80211_check_fast_xmit() or friends) is required to reset the data,
|
||||
* since the per-packet code no longer checks the conditions. This is reflected
|
||||
* by the calls to these functions throughout the rest of the code, and must be
|
||||
* maintained if any of the TX path checks change.
|
||||
*/
|
||||
|
||||
void ieee80211_check_fast_xmit(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_fast_tx build = {}, *fast_tx = NULL, *old;
|
||||
struct ieee80211_local *local = sta->local;
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_hdr *hdr = (void *)build.hdr;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
__le16 fc;
|
||||
|
||||
if (!(local->hw.flags & IEEE80211_HW_SUPPORT_FAST_XMIT))
|
||||
return;
|
||||
|
||||
/* Locking here protects both the pointer itself, and against concurrent
|
||||
* invocations winning data access races to, e.g., the key pointer that
|
||||
* is used.
|
||||
* Without it, the invocation of this function right after the key
|
||||
* pointer changes wouldn't be sufficient, as another CPU could access
|
||||
* the pointer, then stall, and then do the cache update after the CPU
|
||||
* that invalidated the key.
|
||||
* With the locking, such scenarios cannot happen as the check for the
|
||||
* key and the fast-tx assignment are done atomically, so the CPU that
|
||||
* modifies the key will either wait or other one will see the key
|
||||
* cleared/changed already.
|
||||
*/
|
||||
spin_lock_bh(&sta->lock);
|
||||
if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS &&
|
||||
!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) &&
|
||||
sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
goto out;
|
||||
|
||||
if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
|
||||
goto out;
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
|
||||
test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
|
||||
test_sta_flag(sta, WLAN_STA_PS_DELIVER))
|
||||
goto out;
|
||||
|
||||
if (sdata->noack_map)
|
||||
goto out;
|
||||
|
||||
/* fast-xmit doesn't handle fragmentation at all */
|
||||
if (local->hw.wiphy->frag_threshold != (u32)-1 &&
|
||||
!local->ops->set_frag_threshold)
|
||||
goto out;
|
||||
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
if (!chanctx_conf) {
|
||||
rcu_read_unlock();
|
||||
goto out;
|
||||
}
|
||||
build.band = chanctx_conf->def.chan->band;
|
||||
rcu_read_unlock();
|
||||
|
||||
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
/* DA SA BSSID */
|
||||
build.da_offs = offsetof(struct ieee80211_hdr, addr1);
|
||||
build.sa_offs = offsetof(struct ieee80211_hdr, addr2);
|
||||
memcpy(hdr->addr3, sdata->u.ibss.bssid, ETH_ALEN);
|
||||
build.hdr_len = 24;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
|
||||
/* DA SA BSSID */
|
||||
build.da_offs = offsetof(struct ieee80211_hdr, addr1);
|
||||
build.sa_offs = offsetof(struct ieee80211_hdr, addr2);
|
||||
memcpy(hdr->addr3, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
build.hdr_len = 24;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sdata->u.mgd.use_4addr) {
|
||||
/* non-regular ethertype cannot use the fastpath */
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
|
||||
IEEE80211_FCTL_TODS);
|
||||
/* RA TA DA SA */
|
||||
memcpy(hdr->addr1, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
|
||||
build.da_offs = offsetof(struct ieee80211_hdr, addr3);
|
||||
build.sa_offs = offsetof(struct ieee80211_hdr, addr4);
|
||||
build.hdr_len = 30;
|
||||
break;
|
||||
}
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
|
||||
/* BSSID SA DA */
|
||||
memcpy(hdr->addr1, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
build.da_offs = offsetof(struct ieee80211_hdr, addr3);
|
||||
build.sa_offs = offsetof(struct ieee80211_hdr, addr2);
|
||||
build.hdr_len = 24;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
if (sdata->wdev.use_4addr) {
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
|
||||
IEEE80211_FCTL_TODS);
|
||||
/* RA TA DA SA */
|
||||
memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
|
||||
memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
|
||||
build.da_offs = offsetof(struct ieee80211_hdr, addr3);
|
||||
build.sa_offs = offsetof(struct ieee80211_hdr, addr4);
|
||||
build.hdr_len = 30;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_AP:
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
|
||||
/* DA BSSID SA */
|
||||
build.da_offs = offsetof(struct ieee80211_hdr, addr1);
|
||||
memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
|
||||
build.sa_offs = offsetof(struct ieee80211_hdr, addr3);
|
||||
build.hdr_len = 24;
|
||||
break;
|
||||
default:
|
||||
/* not handled on fast-xmit */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sta->sta.wme) {
|
||||
build.hdr_len += 2;
|
||||
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
||||
}
|
||||
|
||||
/* We store the key here so there's no point in using rcu_dereference()
|
||||
* but that's fine because the code that changes the pointers will call
|
||||
* this function after doing so. For a single CPU that would be enough,
|
||||
* for multiple see the comment above.
|
||||
*/
|
||||
build.key = rcu_access_pointer(sta->ptk[sta->ptk_idx]);
|
||||
if (!build.key)
|
||||
build.key = rcu_access_pointer(sdata->default_unicast_key);
|
||||
if (build.key) {
|
||||
bool gen_iv, iv_spc, mmic;
|
||||
|
||||
gen_iv = build.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
iv_spc = build.key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE;
|
||||
mmic = build.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||
|
||||
/* don't handle software crypto */
|
||||
if (!(build.key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
|
||||
goto out;
|
||||
|
||||
switch (build.key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||
/* add fixed key ID */
|
||||
if (gen_iv) {
|
||||
(build.hdr + build.hdr_len)[3] =
|
||||
0x20 | (build.key->conf.keyidx << 6);
|
||||
build.pn_offs = build.hdr_len;
|
||||
}
|
||||
if (gen_iv || iv_spc)
|
||||
build.hdr_len += IEEE80211_CCMP_HDR_LEN;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
/* add fixed key ID */
|
||||
if (gen_iv) {
|
||||
(build.hdr + build.hdr_len)[3] =
|
||||
0x20 | (build.key->conf.keyidx << 6);
|
||||
build.pn_offs = build.hdr_len;
|
||||
}
|
||||
if (gen_iv || iv_spc)
|
||||
build.hdr_len += IEEE80211_GCMP_HDR_LEN;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
/* cannot handle MMIC or IV generation in xmit-fast */
|
||||
if (mmic || gen_iv)
|
||||
goto out;
|
||||
if (iv_spc)
|
||||
build.hdr_len += IEEE80211_TKIP_IV_LEN;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
/* cannot handle IV generation in fast-xmit */
|
||||
if (gen_iv)
|
||||
goto out;
|
||||
if (iv_spc)
|
||||
build.hdr_len += IEEE80211_WEP_IV_LEN;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
||||
WARN(1,
|
||||
"management cipher suite 0x%x enabled for data\n",
|
||||
build.key->conf.cipher);
|
||||
goto out;
|
||||
default:
|
||||
/* we don't know how to generate IVs for this at all */
|
||||
if (WARN_ON(gen_iv))
|
||||
goto out;
|
||||
/* pure hardware keys are OK, of course */
|
||||
if (!(build.key->flags & KEY_FLAG_CIPHER_SCHEME))
|
||||
break;
|
||||
/* cipher scheme might require space allocation */
|
||||
if (iv_spc &&
|
||||
build.key->conf.iv_len > IEEE80211_FAST_XMIT_MAX_IV)
|
||||
goto out;
|
||||
if (iv_spc)
|
||||
build.hdr_len += build.key->conf.iv_len;
|
||||
}
|
||||
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
}
|
||||
|
||||
hdr->frame_control = fc;
|
||||
|
||||
memcpy(build.hdr + build.hdr_len,
|
||||
rfc1042_header, sizeof(rfc1042_header));
|
||||
build.hdr_len += sizeof(rfc1042_header);
|
||||
|
||||
fast_tx = kmemdup(&build, sizeof(build), GFP_ATOMIC);
|
||||
/* if the kmemdup fails, continue w/o fast_tx */
|
||||
if (!fast_tx)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
/* we might have raced against another call to this function */
|
||||
old = rcu_dereference_protected(sta->fast_tx,
|
||||
lockdep_is_held(&sta->lock));
|
||||
rcu_assign_pointer(sta->fast_tx, fast_tx);
|
||||
if (old)
|
||||
kfree_rcu(old, rcu_head);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
}
|
||||
|
||||
void ieee80211_check_fast_xmit_all(struct ieee80211_local *local)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list)
|
||||
ieee80211_check_fast_xmit(sta);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
if (sdata != sta->sdata &&
|
||||
(!sta->sdata->bss || sta->sdata->bss != sdata->bss))
|
||||
continue;
|
||||
ieee80211_check_fast_xmit(sta);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ieee80211_clear_fast_xmit(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_fast_tx *fast_tx;
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
fast_tx = rcu_dereference_protected(sta->fast_tx,
|
||||
lockdep_is_held(&sta->lock));
|
||||
RCU_INIT_POINTER(sta->fast_tx, NULL);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
if (fast_tx)
|
||||
kfree_rcu(fast_tx, rcu_head);
|
||||
}
|
||||
|
||||
static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
||||
struct net_device *dev, struct sta_info *sta,
|
||||
struct ieee80211_fast_tx *fast_tx,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
u16 ethertype = (skb->data[12] << 8) | skb->data[13];
|
||||
int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
|
||||
int hw_headroom = sdata->local->hw.extra_tx_headroom;
|
||||
struct ethhdr eth;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
|
||||
struct ieee80211_tx_data tx;
|
||||
ieee80211_tx_result r;
|
||||
struct tid_ampdu_tx *tid_tx = NULL;
|
||||
u8 tid = IEEE80211_NUM_TIDS;
|
||||
|
||||
/* control port protocol needs a lot of special handling */
|
||||
if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
|
||||
return false;
|
||||
|
||||
/* only RFC 1042 SNAP */
|
||||
if (ethertype < ETH_P_802_3_MIN)
|
||||
return false;
|
||||
|
||||
/* don't handle TX status request here either */
|
||||
if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
|
||||
return false;
|
||||
|
||||
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
||||
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||
tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
|
||||
if (tid_tx &&
|
||||
!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* after this point (skb is modified) we cannot return false */
|
||||
|
||||
if (skb_shared(skb)) {
|
||||
struct sk_buff *tmp_skb = skb;
|
||||
|
||||
skb = skb_clone(skb, GFP_ATOMIC);
|
||||
kfree_skb(tmp_skb);
|
||||
|
||||
if (!skb)
|
||||
return true;
|
||||
}
|
||||
|
||||
ieee80211_tx_stats(dev, skb->len + extra_head);
|
||||
|
||||
/* will not be crypto-handled beyond what we do here, so use false
|
||||
* as the may-encrypt argument for the resize to not account for
|
||||
* more room than we already have in 'extra_head'
|
||||
*/
|
||||
if (unlikely(ieee80211_skb_resize(sdata, skb,
|
||||
max_t(int, extra_head + hw_headroom -
|
||||
skb_headroom(skb), 0),
|
||||
false))) {
|
||||
kfree_skb(skb);
|
||||
return true;
|
||||
}
|
||||
|
||||
memcpy(ð, skb->data, ETH_HLEN - 2);
|
||||
hdr = (void *)skb_push(skb, extra_head);
|
||||
memcpy(skb->data, fast_tx->hdr, fast_tx->hdr_len);
|
||||
memcpy(skb->data + fast_tx->da_offs, eth.h_dest, ETH_ALEN);
|
||||
memcpy(skb->data + fast_tx->sa_offs, eth.h_source, ETH_ALEN);
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->band = fast_tx->band;
|
||||
info->control.vif = &sdata->vif;
|
||||
info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
|
||||
IEEE80211_TX_CTL_DONTFRAG |
|
||||
(tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
|
||||
|
||||
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
||||
*ieee80211_get_qos_ctl(hdr) = tid;
|
||||
hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
|
||||
} else {
|
||||
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
||||
hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number);
|
||||
sdata->sequence_number += 0x10;
|
||||
}
|
||||
|
||||
sta->tx_msdu[tid]++;
|
||||
|
||||
info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
|
||||
|
||||
__skb_queue_head_init(&tx.skbs);
|
||||
|
||||
tx.flags = IEEE80211_TX_UNICAST;
|
||||
tx.local = local;
|
||||
tx.sdata = sdata;
|
||||
tx.sta = sta;
|
||||
tx.key = fast_tx->key;
|
||||
|
||||
if (fast_tx->key)
|
||||
info->control.hw_key = &fast_tx->key->conf;
|
||||
|
||||
if (!(local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) {
|
||||
tx.skb = skb;
|
||||
r = ieee80211_tx_h_rate_ctrl(&tx);
|
||||
skb = tx.skb;
|
||||
tx.skb = NULL;
|
||||
|
||||
if (r != TX_CONTINUE) {
|
||||
if (r != TX_QUEUED)
|
||||
kfree_skb(skb);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* statistics normally done by ieee80211_tx_h_stats (but that
|
||||
* has to consider fragmentation, so is more complex)
|
||||
*/
|
||||
sta->tx_bytes[skb_get_queue_mapping(skb)] += skb->len;
|
||||
sta->tx_packets[skb_get_queue_mapping(skb)]++;
|
||||
|
||||
if (fast_tx->pn_offs) {
|
||||
u64 pn;
|
||||
u8 *crypto_hdr = skb->data + fast_tx->pn_offs;
|
||||
|
||||
switch (fast_tx->key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||
pn = atomic64_inc_return(&fast_tx->key->u.ccmp.tx_pn);
|
||||
crypto_hdr[0] = pn;
|
||||
crypto_hdr[1] = pn >> 8;
|
||||
crypto_hdr[4] = pn >> 16;
|
||||
crypto_hdr[5] = pn >> 24;
|
||||
crypto_hdr[6] = pn >> 32;
|
||||
crypto_hdr[7] = pn >> 40;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
pn = atomic64_inc_return(&fast_tx->key->u.gcmp.tx_pn);
|
||||
crypto_hdr[0] = pn;
|
||||
crypto_hdr[1] = pn >> 8;
|
||||
crypto_hdr[4] = pn >> 16;
|
||||
crypto_hdr[5] = pn >> 24;
|
||||
crypto_hdr[6] = pn >> 32;
|
||||
crypto_hdr[7] = pn >> 40;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
sdata = container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data, u.ap);
|
||||
|
||||
__skb_queue_tail(&tx.skbs, skb);
|
||||
ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
u32 info_flags)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct sta_info *sta;
|
||||
struct sk_buff *next;
|
||||
|
||||
if (unlikely(skb->len < ETH_HLEN)) {
|
||||
kfree_skb(skb);
|
||||
@ -2401,20 +2858,67 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
|
||||
kfree_skb(skb);
|
||||
goto out;
|
||||
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
|
||||
goto out_free;
|
||||
|
||||
if (!IS_ERR_OR_NULL(sta)) {
|
||||
struct ieee80211_fast_tx *fast_tx;
|
||||
|
||||
fast_tx = rcu_dereference(sta->fast_tx);
|
||||
|
||||
if (fast_tx &&
|
||||
ieee80211_xmit_fast(sdata, dev, sta, fast_tx, skb))
|
||||
goto out;
|
||||
}
|
||||
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
|
||||
if (IS_ERR(skb))
|
||||
goto out;
|
||||
if (skb_is_gso(skb)) {
|
||||
struct sk_buff *segs;
|
||||
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
dev->trans_start = jiffies;
|
||||
segs = skb_gso_segment(skb, 0);
|
||||
if (IS_ERR(segs)) {
|
||||
goto out_free;
|
||||
} else if (segs) {
|
||||
consume_skb(skb);
|
||||
skb = segs;
|
||||
}
|
||||
} else {
|
||||
/* we cannot process non-linear frames on this path */
|
||||
if (skb_linearize(skb)) {
|
||||
kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ieee80211_xmit(sdata, sta, skb);
|
||||
/* the frame could be fragmented, software-encrypted, and other
|
||||
* things so we cannot really handle checksum offload with it -
|
||||
* fix it up in software before we handle anything else.
|
||||
*/
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
skb_set_transport_header(skb,
|
||||
skb_checksum_start_offset(skb));
|
||||
if (skb_checksum_help(skb))
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
|
||||
next = skb;
|
||||
while (next) {
|
||||
skb = next;
|
||||
next = skb->next;
|
||||
|
||||
skb->prev = NULL;
|
||||
skb->next = NULL;
|
||||
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
|
||||
if (IS_ERR(skb))
|
||||
goto out;
|
||||
|
||||
ieee80211_tx_stats(dev, skb->len);
|
||||
|
||||
ieee80211_xmit(sdata, sta, skb);
|
||||
}
|
||||
goto out;
|
||||
out_free:
|
||||
kfree_skb(skb);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
@ -698,19 +698,20 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
|
||||
EXPORT_SYMBOL(cfg80211_chandef_usable);
|
||||
|
||||
/*
|
||||
* For GO only, check if the channel can be used under permissive conditions
|
||||
* mandated by the some regulatory bodies, i.e., the channel is marked with
|
||||
* IEEE80211_CHAN_GO_CONCURRENT and there is an additional station interface
|
||||
* Check if the channel can be used under permissive conditions mandated by
|
||||
* some regulatory bodies, i.e., the channel is marked with
|
||||
* IEEE80211_CHAN_IR_CONCURRENT and there is an additional station interface
|
||||
* associated to an AP on the same channel or on the same UNII band
|
||||
* (assuming that the AP is an authorized master).
|
||||
* In addition allow the GO to operate on a channel on which indoor operation is
|
||||
* In addition allow operation on a channel on which indoor operation is
|
||||
* allowed, iff we are currently operating in an indoor environment.
|
||||
*/
|
||||
static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
|
||||
static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
|
||||
enum nl80211_iftype iftype,
|
||||
struct ieee80211_channel *chan)
|
||||
{
|
||||
struct wireless_dev *wdev_iter;
|
||||
struct wiphy *wiphy = wiphy_idx_to_wiphy(rdev->wiphy_idx);
|
||||
struct wireless_dev *wdev;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
@ -718,32 +719,48 @@ static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
|
||||
!(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
|
||||
return false;
|
||||
|
||||
/* only valid for GO and TDLS off-channel (station/p2p-CL) */
|
||||
if (iftype != NL80211_IFTYPE_P2P_GO &&
|
||||
iftype != NL80211_IFTYPE_STATION &&
|
||||
iftype != NL80211_IFTYPE_P2P_CLIENT)
|
||||
return false;
|
||||
|
||||
if (regulatory_indoor_allowed() &&
|
||||
(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
|
||||
return true;
|
||||
|
||||
if (!(chan->flags & IEEE80211_CHAN_GO_CONCURRENT))
|
||||
if (!(chan->flags & IEEE80211_CHAN_IR_CONCURRENT))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Generally, it is possible to rely on another device/driver to allow
|
||||
* the GO concurrent relaxation, however, since the device can further
|
||||
* the IR concurrent relaxation, however, since the device can further
|
||||
* enforce the relaxation (by doing a similar verifications as this),
|
||||
* and thus fail the GO instantiation, consider only the interfaces of
|
||||
* the current registered device.
|
||||
*/
|
||||
list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
struct ieee80211_channel *other_chan = NULL;
|
||||
int r1, r2;
|
||||
|
||||
if (wdev_iter->iftype != NL80211_IFTYPE_STATION ||
|
||||
!netif_running(wdev_iter->netdev))
|
||||
continue;
|
||||
wdev_lock(wdev);
|
||||
if (wdev->iftype == NL80211_IFTYPE_STATION &&
|
||||
wdev->current_bss)
|
||||
other_chan = wdev->current_bss->pub.channel;
|
||||
|
||||
wdev_lock(wdev_iter);
|
||||
if (wdev_iter->current_bss)
|
||||
other_chan = wdev_iter->current_bss->pub.channel;
|
||||
wdev_unlock(wdev_iter);
|
||||
/*
|
||||
* If a GO already operates on the same GO_CONCURRENT channel,
|
||||
* this one (maybe the same one) can beacon as well. We allow
|
||||
* the operation even if the station we relied on with
|
||||
* GO_CONCURRENT is disconnected now. But then we must make sure
|
||||
* we're not outdoor on an indoor-only channel.
|
||||
*/
|
||||
if (iftype == NL80211_IFTYPE_P2P_GO &&
|
||||
wdev->iftype == NL80211_IFTYPE_P2P_GO &&
|
||||
wdev->beacon_interval &&
|
||||
!(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
|
||||
other_chan = wdev->chandef.chan;
|
||||
wdev_unlock(wdev);
|
||||
|
||||
if (!other_chan)
|
||||
continue;
|
||||
@ -784,7 +801,6 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
|
||||
struct cfg80211_chan_def *chandef,
|
||||
enum nl80211_iftype iftype)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
bool res;
|
||||
u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
|
||||
IEEE80211_CHAN_RADAR;
|
||||
@ -792,13 +808,12 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
|
||||
trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
|
||||
|
||||
/*
|
||||
* Under certain conditions suggested by the some regulatory bodies
|
||||
* a GO can operate on channels marked with IEEE80211_NO_IR
|
||||
* so set this flag only if such relaxations are not enabled and
|
||||
* the conditions are not met.
|
||||
* Under certain conditions suggested by some regulatory bodies a
|
||||
* GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
|
||||
* only if such relaxations are not enabled and the conditions are not
|
||||
* met.
|
||||
*/
|
||||
if (iftype != NL80211_IFTYPE_P2P_GO ||
|
||||
!cfg80211_go_permissive_chan(rdev, chandef->chan))
|
||||
if (!cfg80211_ir_permissive_chan(wiphy, iftype, chandef->chan))
|
||||
prohibited_flags |= IEEE80211_CHAN_NO_IR;
|
||||
|
||||
if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
|
||||
|
@ -639,8 +639,8 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
|
||||
if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
|
||||
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
|
||||
goto nla_put_failure;
|
||||
if ((chan->flags & IEEE80211_CHAN_GO_CONCURRENT) &&
|
||||
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_GO_CONCURRENT))
|
||||
if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
|
||||
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
|
||||
goto nla_put_failure;
|
||||
if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
|
||||
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
|
||||
@ -4061,7 +4061,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
|
||||
return -EINVAL;
|
||||
break;
|
||||
case CFG80211_STA_MESH_PEER_USER:
|
||||
if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
|
||||
if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
|
||||
params->plink_action != NL80211_PLINK_ACTION_BLOCK)
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
@ -989,8 +989,8 @@ static u32 map_regdom_flags(u32 rd_flags)
|
||||
channel_flags |= IEEE80211_CHAN_NO_OFDM;
|
||||
if (rd_flags & NL80211_RRF_NO_OUTDOOR)
|
||||
channel_flags |= IEEE80211_CHAN_INDOOR_ONLY;
|
||||
if (rd_flags & NL80211_RRF_GO_CONCURRENT)
|
||||
channel_flags |= IEEE80211_CHAN_GO_CONCURRENT;
|
||||
if (rd_flags & NL80211_RRF_IR_CONCURRENT)
|
||||
channel_flags |= IEEE80211_CHAN_IR_CONCURRENT;
|
||||
if (rd_flags & NL80211_RRF_NO_HT40MINUS)
|
||||
channel_flags |= IEEE80211_CHAN_NO_HT40MINUS;
|
||||
if (rd_flags & NL80211_RRF_NO_HT40PLUS)
|
||||
|
Loading…
Reference in New Issue
Block a user