summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-04-02 09:26:51 +0300
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-04-02 09:26:51 +0300
commitb916693a7731670429609854c32de1a71775d070 (patch)
tree1007e5aedd88f94bdb6a55e0f7b4b8e3aee7c29d
parent21023b1e7f9862015fd8c91d5619217da8d9a06a (diff)
parent2c44be81f0fc147eed9dc63e2601318b2c007aeb (diff)
Merge tag 'mac80211-next-for-davem-2015-03-30' into iwlwifi-next
Lots of updates for net-next; along with the usual flurry of small fixes, cleanups and internal features we have: * VHT support for TDLS and IBSS (conditional on drivers though) * first TX performance improvements (the biggest will come later) * many suspend/resume (race) fixes * name_assign_type support from Tom Gundersen
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/powerpc/include/asm/asm-compat.h4
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h2
-rw-r--r--arch/powerpc/net/Makefile2
-rw-r--r--arch/powerpc/net/bpf_jit.h64
-rw-r--r--arch/powerpc/net/bpf_jit_asm.S (renamed from arch/powerpc/net/bpf_jit_64.S)70
-rw-r--r--arch/powerpc/net/bpf_jit_comp.c46
-rw-r--r--drivers/net/bonding/bond_main.c6
-rw-r--r--drivers/net/dsa/mv88e6171.c18
-rw-r--r--drivers/net/dsa/mv88e6352.c77
-rw-r--r--drivers/net/dsa/mv88e6xxx.c53
-rw-r--r--drivers/net/dsa/mv88e6xxx.h6
-rw-r--r--drivers/net/ethernet/altera/altera_tse_main.c20
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig8
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c14
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.h4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2_fw.h4
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c6
-rw-r--r--drivers/net/ethernet/broadcom/cnic_if.h8
-rw-r--r--drivers/net/ethernet/brocade/Kconfig8
-rw-r--r--drivers/net/ethernet/brocade/Makefile2
-rw-r--r--drivers/net/ethernet/brocade/bna/Kconfig12
-rw-r--r--drivers/net/ethernet/brocade/bna/Makefile3
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cee.c7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cee.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_cs.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs_cna.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs_status.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.c9
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_msgq.c7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_msgq.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi_cna.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi_enet.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfi_reg.h13
-rw-r--r--drivers/net/ethernet/brocade/bna/bna.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_enet.c7
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_hw_defs.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_tx_rx.c7
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_types.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c11
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.h9
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_debugfs.c7
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_ethtool.c7
-rw-r--r--drivers/net/ethernet/brocade/bna/cna.h11
-rw-r--r--drivers/net/ethernet/brocade/bna/cna_fwimg.c7
-rw-r--r--drivers/net/ethernet/cadence/macb.c18
-rw-r--r--drivers/net/ethernet/cadence/macb.h15
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h40
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c294
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c2
-rw-r--r--drivers/net/usb/hso.c13
-rw-r--r--drivers/net/usb/r8152.c131
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c3
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c15
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.h1
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.h1
-rw-r--r--drivers/net/wireless/cw1200/sta.c4
-rw-r--r--drivers/net/wireless/ipw2x00/Kconfig2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c15
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex_legacy.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h4
-rw-r--r--drivers/net/wireless/libertas/cfg.c6
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c103
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c13
-rw-r--r--drivers/net/wireless/mwifiex/main.c6
-rw-r--r--drivers/net/wireless/mwifiex/main.h1
-rw-r--r--drivers/net/wireless/orinoco/Kconfig2
-rw-r--r--drivers/net/wireless/ti/wl18xx/event.c4
-rw-r--r--drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c6
-rw-r--r--include/linux/igmp.h2
-rw-r--r--include/linux/skbuff.h3
-rw-r--r--include/net/cfg80211.h65
-rw-r--r--include/net/iw_handler.h22
-rw-r--r--include/net/mac80211.h150
-rw-r--r--include/uapi/linux/nl80211.h34
-rw-r--r--net/batman-adv/gateway_client.c19
-rw-r--r--net/bridge/br_netlink.c46
-rw-r--r--net/compat.c10
-rw-r--r--net/core/ethtool.c2
-rw-r--r--net/core/skbuff.c9
-rw-r--r--net/ipv4/igmp.c52
-rw-r--r--net/ipv4/tcp_cong.c2
-rw-r--r--net/ipv6/raw.c2
-rw-r--r--net/mac80211/aes_ccm.c12
-rw-r--r--net/mac80211/aes_gcm.c12
-rw-r--r--net/mac80211/aes_gmac.c4
-rw-r--r--net/mac80211/agg-rx.c8
-rw-r--r--net/mac80211/agg-tx.c14
-rw-r--r--net/mac80211/cfg.c97
-rw-r--r--net/mac80211/debugfs.c170
-rw-r--r--net/mac80211/debugfs_netdev.c2
-rw-r--r--net/mac80211/debugfs_sta.c134
-rw-r--r--net/mac80211/driver-ops.h12
-rw-r--r--net/mac80211/ht.c2
-rw-r--r--net/mac80211/ibss.c341
-rw-r--r--net/mac80211/ieee80211_i.h39
-rw-r--r--net/mac80211/iface.c4
-rw-r--r--net/mac80211/key.c1
-rw-r--r--net/mac80211/key.h2
-rw-r--r--net/mac80211/main.c4
-rw-r--r--net/mac80211/mesh.c3
-rw-r--r--net/mac80211/mesh_plink.c10
-rw-r--r--net/mac80211/mlme.c212
-rw-r--r--net/mac80211/pm.c28
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c6
-rw-r--r--net/mac80211/rx.c17
-rw-r--r--net/mac80211/scan.c25
-rw-r--r--net/mac80211/sta_info.c56
-rw-r--r--net/mac80211/sta_info.h22
-rw-r--r--net/mac80211/status.c74
-rw-r--r--net/mac80211/tdls.c155
-rw-r--r--net/mac80211/trace.h14
-rw-r--r--net/mac80211/tx.c266
-rw-r--r--net/mac80211/util.c128
-rw-r--r--net/mac80211/vht.c4
-rw-r--r--net/mac80211/wpa.c13
-rw-r--r--net/netfilter/nf_conntrack_amanda.c10
-rw-r--r--net/netfilter/xt_string.c3
-rw-r--r--net/sched/em_text.c3
-rw-r--r--net/wireless/Kconfig8
-rw-r--r--net/wireless/ibss.c2
-rw-r--r--net/wireless/mlme.c6
-rw-r--r--net/wireless/nl80211.c84
-rw-r--r--net/wireless/rdev-ops.h5
-rw-r--r--net/wireless/reg.c111
-rw-r--r--net/wireless/reg.h15
-rw-r--r--net/wireless/scan.c302
-rw-r--r--net/wireless/sme.c16
-rw-r--r--net/wireless/trace.h32
-rw-r--r--net/wireless/util.c130
-rw-r--r--net/wireless/wext-compat.c18
-rw-r--r--net/wireless/wext-compat.h6
142 files changed, 2735 insertions, 1686 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 22b0940494bb..5084bdcc6046 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -126,7 +126,7 @@ config PPC
select IRQ_FORCED_THREADING
select HAVE_RCU_TABLE_FREE if SMP
select HAVE_SYSCALL_TRACEPOINTS
- select HAVE_BPF_JIT if PPC64
+ select HAVE_BPF_JIT
select HAVE_ARCH_JUMP_LABEL
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select ARCH_HAS_GCOV_PROFILE_ALL
diff --git a/arch/powerpc/include/asm/asm-compat.h b/arch/powerpc/include/asm/asm-compat.h
index 21be8ae8f809..dc85dcb891cf 100644
--- a/arch/powerpc/include/asm/asm-compat.h
+++ b/arch/powerpc/include/asm/asm-compat.h
@@ -23,6 +23,8 @@
#define PPC_STL stringify_in_c(std)
#define PPC_STLU stringify_in_c(stdu)
#define PPC_LCMPI stringify_in_c(cmpdi)
+#define PPC_LCMPLI stringify_in_c(cmpldi)
+#define PPC_LCMP stringify_in_c(cmpd)
#define PPC_LONG stringify_in_c(.llong)
#define PPC_LONG_ALIGN stringify_in_c(.balign 8)
#define PPC_TLNEI stringify_in_c(tdnei)
@@ -52,6 +54,8 @@
#define PPC_STL stringify_in_c(stw)
#define PPC_STLU stringify_in_c(stwu)
#define PPC_LCMPI stringify_in_c(cmpwi)
+#define PPC_LCMPLI stringify_in_c(cmplwi)
+#define PPC_LCMP stringify_in_c(cmpw)
#define PPC_LONG stringify_in_c(.long)
#define PPC_LONG_ALIGN stringify_in_c(.balign 4)
#define PPC_TLNEI stringify_in_c(twnei)
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 03cd858a401c..2eadde0b98fb 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -212,6 +212,8 @@
#define PPC_INST_LWZ 0x80000000
#define PPC_INST_STD 0xf8000000
#define PPC_INST_STDU 0xf8000001
+#define PPC_INST_STW 0x90000000
+#define PPC_INST_STWU 0x94000000
#define PPC_INST_MFLR 0x7c0802a6
#define PPC_INST_MTLR 0x7c0803a6
#define PPC_INST_CMPWI 0x2c000000
diff --git a/arch/powerpc/net/Makefile b/arch/powerpc/net/Makefile
index 266b3950c3ac..1306a58ac541 100644
--- a/arch/powerpc/net/Makefile
+++ b/arch/powerpc/net/Makefile
@@ -1,4 +1,4 @@
#
# Arch-specific network modules
#
-obj-$(CONFIG_BPF_JIT) += bpf_jit_64.o bpf_jit_comp.o
+obj-$(CONFIG_BPF_JIT) += bpf_jit_asm.o bpf_jit_comp.o
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index c406aa95b2bc..889fd199a821 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -10,12 +10,25 @@
#ifndef _BPF_JIT_H
#define _BPF_JIT_H
+#ifdef CONFIG_PPC64
+#define BPF_PPC_STACK_R3_OFF 48
#define BPF_PPC_STACK_LOCALS 32
#define BPF_PPC_STACK_BASIC (48+64)
#define BPF_PPC_STACK_SAVE (18*8)
#define BPF_PPC_STACKFRAME (BPF_PPC_STACK_BASIC+BPF_PPC_STACK_LOCALS+ \
BPF_PPC_STACK_SAVE)
#define BPF_PPC_SLOWPATH_FRAME (48+64)
+#else
+#define BPF_PPC_STACK_R3_OFF 24
+#define BPF_PPC_STACK_LOCALS 16
+#define BPF_PPC_STACK_BASIC (24+32)
+#define BPF_PPC_STACK_SAVE (18*4)
+#define BPF_PPC_STACKFRAME (BPF_PPC_STACK_BASIC+BPF_PPC_STACK_LOCALS+ \
+ BPF_PPC_STACK_SAVE)
+#define BPF_PPC_SLOWPATH_FRAME (24+32)
+#endif
+
+#define REG_SZ (BITS_PER_LONG/8)
/*
* Generated code register usage:
@@ -57,7 +70,11 @@ DECLARE_LOAD_FUNC(sk_load_half);
DECLARE_LOAD_FUNC(sk_load_byte);
DECLARE_LOAD_FUNC(sk_load_byte_msh);
+#ifdef CONFIG_PPC64
#define FUNCTION_DESCR_SIZE 24
+#else
+#define FUNCTION_DESCR_SIZE 0
+#endif
/*
* 16-bit immediate helper macros: HA() is for use with sign-extending instrs
@@ -86,7 +103,12 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh);
#define PPC_LIS(r, i) PPC_ADDIS(r, 0, i)
#define PPC_STD(r, base, i) EMIT(PPC_INST_STD | ___PPC_RS(r) | \
___PPC_RA(base) | ((i) & 0xfffc))
-
+#define PPC_STDU(r, base, i) EMIT(PPC_INST_STDU | ___PPC_RS(r) | \
+ ___PPC_RA(base) | ((i) & 0xfffc))
+#define PPC_STW(r, base, i) EMIT(PPC_INST_STW | ___PPC_RS(r) | \
+ ___PPC_RA(base) | ((i) & 0xfffc))
+#define PPC_STWU(r, base, i) EMIT(PPC_INST_STWU | ___PPC_RS(r) | \
+ ___PPC_RA(base) | ((i) & 0xfffc))
#define PPC_LBZ(r, base, i) EMIT(PPC_INST_LBZ | ___PPC_RT(r) | \
___PPC_RA(base) | IMM_L(i))
@@ -98,6 +120,17 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh);
___PPC_RA(base) | IMM_L(i))
#define PPC_LHBRX(r, base, b) EMIT(PPC_INST_LHBRX | ___PPC_RT(r) | \
___PPC_RA(base) | ___PPC_RB(b))
+
+#ifdef CONFIG_PPC64
+#define PPC_BPF_LL(r, base, i) do { PPC_LD(r, base, i); } while(0)
+#define PPC_BPF_STL(r, base, i) do { PPC_STD(r, base, i); } while(0)
+#define PPC_BPF_STLU(r, base, i) do { PPC_STDU(r, base, i); } while(0)
+#else
+#define PPC_BPF_LL(r, base, i) do { PPC_LWZ(r, base, i); } while(0)
+#define PPC_BPF_STL(r, base, i) do { PPC_STW(r, base, i); } while(0)
+#define PPC_BPF_STLU(r, base, i) do { PPC_STWU(r, base, i); } while(0)
+#endif
+
/* Convenience helpers for the above with 'far' offsets: */
#define PPC_LBZ_OFFS(r, base, i) do { if ((i) < 32768) PPC_LBZ(r, base, i); \
else { PPC_ADDIS(r, base, IMM_HA(i)); \
@@ -115,6 +148,29 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh);
else { PPC_ADDIS(r, base, IMM_HA(i)); \
PPC_LHZ(r, r, IMM_L(i)); } } while(0)
+#ifdef CONFIG_PPC64
+#define PPC_LL_OFFS(r, base, i) do { PPC_LD_OFFS(r, base, i); } while(0)
+#else
+#define PPC_LL_OFFS(r, base, i) do { PPC_LWZ_OFFS(r, base, i); } while(0)
+#endif
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_PPC64
+#define PPC_BPF_LOAD_CPU(r) \
+ do { BUILD_BUG_ON(FIELD_SIZEOF(struct paca_struct, paca_index) != 2); \
+ PPC_LHZ_OFFS(r, 13, offsetof(struct paca_struct, paca_index)); \
+ } while (0)
+#else
+#define PPC_BPF_LOAD_CPU(r) \
+ do { BUILD_BUG_ON(FIELD_SIZEOF(struct thread_info, cpu) != 4); \
+ PPC_LHZ_OFFS(r, (1 & ~(THREAD_SIZE - 1)), \
+ offsetof(struct thread_info, cpu)); \
+ } while(0)
+#endif
+#else
+#define PPC_BPF_LOAD_CPU(r) do { PPC_LI(r, 0); } while(0)
+#endif
+
#define PPC_CMPWI(a, i) EMIT(PPC_INST_CMPWI | ___PPC_RA(a) | IMM_L(i))
#define PPC_CMPDI(a, i) EMIT(PPC_INST_CMPDI | ___PPC_RA(a) | IMM_L(i))
#define PPC_CMPLWI(a, i) EMIT(PPC_INST_CMPLWI | ___PPC_RA(a) | IMM_L(i))
@@ -196,6 +252,12 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh);
PPC_ORI(d, d, (uintptr_t)(i) & 0xffff); \
} } while (0);
+#ifdef CONFIG_PPC64
+#define PPC_FUNC_ADDR(d,i) do { PPC_LI64(d, i); } while(0)
+#else
+#define PPC_FUNC_ADDR(d,i) do { PPC_LI32(d, i); } while(0)
+#endif
+
#define PPC_LHBRX_OFFS(r, base, i) \
do { PPC_LI32(r, i); PPC_LHBRX(r, r, base); } while(0)
#ifdef __LITTLE_ENDIAN__
diff --git a/arch/powerpc/net/bpf_jit_64.S b/arch/powerpc/net/bpf_jit_asm.S
index 8f87d9217122..8ff5a3b5d1c3 100644
--- a/arch/powerpc/net/bpf_jit_64.S
+++ b/arch/powerpc/net/bpf_jit_asm.S
@@ -34,13 +34,13 @@
*/
.globl sk_load_word
sk_load_word:
- cmpdi r_addr, 0
+ PPC_LCMPI r_addr, 0
blt bpf_slow_path_word_neg
.globl sk_load_word_positive_offset
sk_load_word_positive_offset:
/* Are we accessing past headlen? */
subi r_scratch1, r_HL, 4
- cmpd r_scratch1, r_addr
+ PPC_LCMP r_scratch1, r_addr
blt bpf_slow_path_word
/* Nope, just hitting the header. cr0 here is eq or gt! */
#ifdef __LITTLE_ENDIAN__
@@ -52,12 +52,12 @@ sk_load_word_positive_offset:
.globl sk_load_half
sk_load_half:
- cmpdi r_addr, 0
+ PPC_LCMPI r_addr, 0
blt bpf_slow_path_half_neg
.globl sk_load_half_positive_offset
sk_load_half_positive_offset:
subi r_scratch1, r_HL, 2
- cmpd r_scratch1, r_addr
+ PPC_LCMP r_scratch1, r_addr
blt bpf_slow_path_half
#ifdef __LITTLE_ENDIAN__
lhbrx r_A, r_D, r_addr
@@ -68,11 +68,11 @@ sk_load_half_positive_offset:
.globl sk_load_byte
sk_load_byte:
- cmpdi r_addr, 0
+ PPC_LCMPI r_addr, 0
blt bpf_slow_path_byte_neg
.globl sk_load_byte_positive_offset
sk_load_byte_positive_offset:
- cmpd r_HL, r_addr
+ PPC_LCMP r_HL, r_addr
ble bpf_slow_path_byte
lbzx r_A, r_D, r_addr
blr
@@ -83,11 +83,11 @@ sk_load_byte_positive_offset:
*/
.globl sk_load_byte_msh
sk_load_byte_msh:
- cmpdi r_addr, 0
+ PPC_LCMPI r_addr, 0
blt bpf_slow_path_byte_msh_neg
.globl sk_load_byte_msh_positive_offset
sk_load_byte_msh_positive_offset:
- cmpd r_HL, r_addr
+ PPC_LCMP r_HL, r_addr
ble bpf_slow_path_byte_msh
lbzx r_X, r_D, r_addr
rlwinm r_X, r_X, 2, 32-4-2, 31-2
@@ -101,13 +101,13 @@ sk_load_byte_msh_positive_offset:
*/
#define bpf_slow_path_common(SIZE) \
mflr r0; \
- std r0, 16(r1); \
+ PPC_STL r0, PPC_LR_STKOFF(r1); \
/* R3 goes in parameter space of caller's frame */ \
- std r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
- std r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
- std r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
- addi r5, r1, BPF_PPC_STACK_BASIC+(2*8); \
- stdu r1, -BPF_PPC_SLOWPATH_FRAME(r1); \
+ PPC_STL r_skb, (BPF_PPC_STACKFRAME+BPF_PPC_STACK_R3_OFF)(r1); \
+ PPC_STL r_A, (BPF_PPC_STACK_BASIC+(0*REG_SZ))(r1); \
+ PPC_STL r_X, (BPF_PPC_STACK_BASIC+(1*REG_SZ))(r1); \
+ addi r5, r1, BPF_PPC_STACK_BASIC+(2*REG_SZ); \
+ PPC_STLU r1, -BPF_PPC_SLOWPATH_FRAME(r1); \
/* R3 = r_skb, as passed */ \
mr r4, r_addr; \
li r6, SIZE; \
@@ -115,19 +115,19 @@ sk_load_byte_msh_positive_offset:
nop; \
/* R3 = 0 on success */ \
addi r1, r1, BPF_PPC_SLOWPATH_FRAME; \
- ld r0, 16(r1); \
- ld r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
- ld r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
+ PPC_LL r0, PPC_LR_STKOFF(r1); \
+ PPC_LL r_A, (BPF_PPC_STACK_BASIC+(0*REG_SZ))(r1); \
+ PPC_LL r_X, (BPF_PPC_STACK_BASIC+(1*REG_SZ))(r1); \
mtlr r0; \
- cmpdi r3, 0; \
+ PPC_LCMPI r3, 0; \
blt bpf_error; /* cr0 = LT */ \
- ld r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
+ PPC_LL r_skb, (BPF_PPC_STACKFRAME+BPF_PPC_STACK_R3_OFF)(r1); \
/* Great success! */
bpf_slow_path_word:
bpf_slow_path_common(4)
/* Data value is on stack, and cr0 != LT */
- lwz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
+ lwz r_A, BPF_PPC_STACK_BASIC+(2*REG_SZ)(r1)
blr
bpf_slow_path_half:
@@ -154,12 +154,12 @@ bpf_slow_path_byte_msh:
*/
#define sk_negative_common(SIZE) \
mflr r0; \
- std r0, 16(r1); \
+ PPC_STL r0, PPC_LR_STKOFF(r1); \
/* R3 goes in parameter space of caller's frame */ \
- std r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
- std r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
- std r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
- stdu r1, -BPF_PPC_SLOWPATH_FRAME(r1); \
+ PPC_STL r_skb, (BPF_PPC_STACKFRAME+BPF_PPC_STACK_R3_OFF)(r1); \
+ PPC_STL r_A, (BPF_PPC_STACK_BASIC+(0*REG_SZ))(r1); \
+ PPC_STL r_X, (BPF_PPC_STACK_BASIC+(1*REG_SZ))(r1); \
+ PPC_STLU r1, -BPF_PPC_SLOWPATH_FRAME(r1); \
/* R3 = r_skb, as passed */ \
mr r4, r_addr; \
li r5, SIZE; \
@@ -167,19 +167,19 @@ bpf_slow_path_byte_msh:
nop; \
/* R3 != 0 on success */ \
addi r1, r1, BPF_PPC_SLOWPATH_FRAME; \
- ld r0, 16(r1); \
- ld r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
- ld r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
+ PPC_LL r0, PPC_LR_STKOFF(r1); \
+ PPC_LL r_A, (BPF_PPC_STACK_BASIC+(0*REG_SZ))(r1); \
+ PPC_LL r_X, (BPF_PPC_STACK_BASIC+(1*REG_SZ))(r1); \
mtlr r0; \
- cmpldi r3, 0; \
+ PPC_LCMPLI r3, 0; \
beq bpf_error_slow; /* cr0 = EQ */ \
mr r_addr, r3; \
- ld r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
+ PPC_LL r_skb, (BPF_PPC_STACKFRAME+BPF_PPC_STACK_R3_OFF)(r1); \
/* Great success! */
bpf_slow_path_word_neg:
lis r_scratch1,-32 /* SKF_LL_OFF */
- cmpd r_addr, r_scratch1 /* addr < SKF_* */
+ PPC_LCMP r_addr, r_scratch1 /* addr < SKF_* */
blt bpf_error /* cr0 = LT */
.globl sk_load_word_negative_offset
sk_load_word_negative_offset:
@@ -189,7 +189,7 @@ sk_load_word_negative_offset:
bpf_slow_path_half_neg:
lis r_scratch1,-32 /* SKF_LL_OFF */
- cmpd r_addr, r_scratch1 /* addr < SKF_* */
+ PPC_LCMP r_addr, r_scratch1 /* addr < SKF_* */
blt bpf_error /* cr0 = LT */
.globl sk_load_half_negative_offset
sk_load_half_negative_offset:
@@ -199,7 +199,7 @@ sk_load_half_negative_offset:
bpf_slow_path_byte_neg:
lis r_scratch1,-32 /* SKF_LL_OFF */
- cmpd r_addr, r_scratch1 /* addr < SKF_* */
+ PPC_LCMP r_addr, r_scratch1 /* addr < SKF_* */
blt bpf_error /* cr0 = LT */
.globl sk_load_byte_negative_offset
sk_load_byte_negative_offset:
@@ -209,7 +209,7 @@ sk_load_byte_negative_offset:
bpf_slow_path_byte_msh_neg:
lis r_scratch1,-32 /* SKF_LL_OFF */
- cmpd r_addr, r_scratch1 /* addr < SKF_* */
+ PPC_LCMP r_addr, r_scratch1 /* addr < SKF_* */
blt bpf_error /* cr0 = LT */
.globl sk_load_byte_msh_negative_offset
sk_load_byte_msh_negative_offset:
@@ -221,7 +221,7 @@ sk_load_byte_msh_negative_offset:
bpf_error_slow:
/* fabricate a cr0 = lt */
li r_scratch1, -1
- cmpdi r_scratch1, 0
+ PPC_LCMPI r_scratch1, 0
bpf_error:
/* Entered with cr0 = lt */
li r3, 0
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index d1916b577f2c..17cea18a09d3 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -1,8 +1,9 @@
-/* bpf_jit_comp.c: BPF JIT compiler for PPC64
+/* bpf_jit_comp.c: BPF JIT compiler
*
* Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation
*
* Based on the x86 BPF compiler, by Eric Dumazet (eric.dumazet@gmail.com)
+ * Ported to ppc32 by Denis Kirjanov <kda@linux-powerpc.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -36,11 +37,11 @@ static void bpf_jit_build_prologue(struct bpf_prog *fp, u32 *image,
if (ctx->seen & SEEN_DATAREF) {
/* If we call any helpers (for loads), save LR */
EMIT(PPC_INST_MFLR | __PPC_RT(R0));
- PPC_STD(0, 1, 16);
+ PPC_BPF_STL(0, 1, PPC_LR_STKOFF);
/* Back up non-volatile regs. */
- PPC_STD(r_D, 1, -(8*(32-r_D)));
- PPC_STD(r_HL, 1, -(8*(32-r_HL)));
+ PPC_BPF_STL(r_D, 1, -(REG_SZ*(32-r_D)));
+ PPC_BPF_STL(r_HL, 1, -(REG_SZ*(32-r_HL)));
}
if (ctx->seen & SEEN_MEM) {
/*
@@ -49,11 +50,10 @@ static void bpf_jit_build_prologue(struct bpf_prog *fp, u32 *image,
*/
for (i = r_M; i < (r_M+16); i++) {
if (ctx->seen & (1 << (i-r_M)))
- PPC_STD(i, 1, -(8*(32-i)));
+ PPC_BPF_STL(i, 1, -(REG_SZ*(32-i)));
}
}
- EMIT(PPC_INST_STDU | __PPC_RS(R1) | __PPC_RA(R1) |
- (-BPF_PPC_STACKFRAME & 0xfffc));
+ PPC_BPF_STLU(1, 1, -BPF_PPC_STACKFRAME);
}
if (ctx->seen & SEEN_DATAREF) {
@@ -67,7 +67,7 @@ static void bpf_jit_build_prologue(struct bpf_prog *fp, u32 *image,
data_len));
PPC_LWZ_OFFS(r_HL, r_skb, offsetof(struct sk_buff, len));
PPC_SUB(r_HL, r_HL, r_scratch1);
- PPC_LD_OFFS(r_D, r_skb, offsetof(struct sk_buff, data));
+ PPC_LL_OFFS(r_D, r_skb, offsetof(struct sk_buff, data));
}
if (ctx->seen & SEEN_XREG) {
@@ -99,16 +99,16 @@ static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
if (ctx->seen & (SEEN_MEM | SEEN_DATAREF)) {
PPC_ADDI(1, 1, BPF_PPC_STACKFRAME);
if (ctx->seen & SEEN_DATAREF) {
- PPC_LD(0, 1, 16);
+ PPC_BPF_LL(0, 1, PPC_LR_STKOFF);
PPC_MTLR(0);
- PPC_LD(r_D, 1, -(8*(32-r_D)));
- PPC_LD(r_HL, 1, -(8*(32-r_HL)));
+ PPC_BPF_LL(r_D, 1, -(REG_SZ*(32-r_D)));
+ PPC_BPF_LL(r_HL, 1, -(REG_SZ*(32-r_HL)));
}
if (ctx->seen & SEEN_MEM) {
/* Restore any saved non-vol registers */
for (i = r_M; i < (r_M+16); i++) {
if (ctx->seen & (1 << (i-r_M)))
- PPC_LD(i, 1, -(8*(32-i)));
+ PPC_BPF_LL(i, 1, -(REG_SZ*(32-i)));
}
}
}
@@ -355,7 +355,7 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
ifindex) != 4);
BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
type) != 2);
- PPC_LD_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff,
+ PPC_LL_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff,
dev));
PPC_CMPDI(r_scratch1, 0);
if (ctx->pc_ret0 != -1) {
@@ -411,20 +411,8 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
PPC_SRWI(r_A, r_A, 5);
break;
case BPF_ANC | SKF_AD_CPU:
-#ifdef CONFIG_SMP
- /*
- * PACA ptr is r13:
- * raw_smp_processor_id() = local_paca->paca_index
- */
- BUILD_BUG_ON(FIELD_SIZEOF(struct paca_struct,
- paca_index) != 2);
- PPC_LHZ_OFFS(r_A, 13,
- offsetof(struct paca_struct, paca_index));
-#else
- PPC_LI(r_A, 0);
-#endif
+ PPC_BPF_LOAD_CPU(r_A);
break;
-
/*** Absolute loads from packet header/data ***/
case BPF_LD | BPF_W | BPF_ABS:
func = CHOOSE_LOAD_FUNC(K, sk_load_word);
@@ -437,7 +425,7 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
common_load:
/* Load from [K]. */
ctx->seen |= SEEN_DATAREF;
- PPC_LI64(r_scratch1, func);
+ PPC_FUNC_ADDR(r_scratch1, func);
PPC_MTLR(r_scratch1);
PPC_LI32(r_addr, K);
PPC_BLRL();
@@ -463,7 +451,7 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
* in the helper functions.
*/
ctx->seen |= SEEN_DATAREF | SEEN_XREG;
- PPC_LI64(r_scratch1, func);
+ PPC_FUNC_ADDR(r_scratch1, func);
PPC_MTLR(r_scratch1);
PPC_ADDI(r_addr, r_X, IMM_L(K));
if (K >= 32768)
@@ -685,9 +673,11 @@ void bpf_jit_compile(struct bpf_prog *fp)
if (image) {
bpf_flush_icache(code_base, code_base + (proglen/4));
+#ifdef CONFIG_PPC64
/* Function descriptor nastiness: Address + TOC */
((u64 *)image)[0] = (u64)code_base;
((u64 *)image)[1] = local_paca->kernel_toc;
+#endif
fp->bpf_func = (void *)image;
fp->jited = true;
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b979c265fc51..675b082283d6 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2900,6 +2900,8 @@ static int bond_slave_netdev_event(unsigned long event,
if (old_duplex != slave->duplex)
bond_3ad_adapter_duplex_changed(slave);
}
+ /* Fallthrough */
+ case NETDEV_DOWN:
/* Refresh slave-array if applicable!
* If the setup does not use miimon or arpmon (mode-specific!),
* then these events will not cause the slave-array to be
@@ -2911,10 +2913,6 @@ static int bond_slave_netdev_event(unsigned long event,
if (bond_mode_uses_xmit_hash(bond))
bond_update_slave_arr(bond, NULL);
break;
- case NETDEV_DOWN:
- if (bond_mode_uses_xmit_hash(bond))
- bond_update_slave_arr(bond, NULL);
- break;
case NETDEV_CHANGEMTU:
/* TODO: Should slaves be allowed to
* independently alter their MTU? For
diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c
index aa33d16f2e22..9808c860a797 100644
--- a/drivers/net/dsa/mv88e6171.c
+++ b/drivers/net/dsa/mv88e6171.c
@@ -51,8 +51,11 @@ static int mv88e6171_switch_reset(struct dsa_switch *ds)
/* Wait for transmit queues to drain. */
usleep_range(2000, 4000);
- /* Reset the switch. */
- REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
+ /* Reset the switch. Keep PPU active. The PPU needs to be
+ * active to support indirect phy register accesses through
+ * global registers 0x18 and 0x19.
+ */
+ REG_WRITE(REG_GLOBAL, 0x04, 0xc000);
/* Wait up to one second for reset to complete. */
timeout = jiffies + 1 * HZ;
@@ -83,11 +86,10 @@ static int mv88e6171_setup_global(struct dsa_switch *ds)
int ret;
int i;
- /* Disable the PHY polling unit (since there won't be any
- * external PHYs to poll), don't discard packets with
- * excessive collisions, and mask all interrupt sources.
+ /* Discard packets with excessive collisions, mask all
+ * interrupt sources, enable PPU.
*/
- REG_WRITE(REG_GLOBAL, 0x04, 0x0000);
+ REG_WRITE(REG_GLOBAL, 0x04, 0x6000);
/* Set the default address aging time to 5 minutes, and
* enable address learn messages to be sent to all message
@@ -336,7 +338,7 @@ mv88e6171_phy_read(struct dsa_switch *ds, int port, int regnum)
int ret;
mutex_lock(&ps->phy_mutex);
- ret = mv88e6xxx_phy_read(ds, addr, regnum);
+ ret = mv88e6xxx_phy_read_indirect(ds, addr, regnum);
mutex_unlock(&ps->phy_mutex);
return ret;
}
@@ -350,7 +352,7 @@ mv88e6171_phy_write(struct dsa_switch *ds,
int ret;
mutex_lock(&ps->phy_mutex);
- ret = mv88e6xxx_phy_write(ds, addr, regnum, val);
+ ret = mv88e6xxx_phy_write_indirect(ds, addr, regnum, val);
mutex_unlock(&ps->phy_mutex);
return ret;
}
diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c
index e13adc7b3dda..1ebd8f96072a 100644
--- a/drivers/net/dsa/mv88e6352.c
+++ b/drivers/net/dsa/mv88e6352.c
@@ -22,59 +22,6 @@
#include <net/dsa.h>
#include "mv88e6xxx.h"
-static int mv88e6352_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
-{
- unsigned long timeout = jiffies + HZ / 10;
-
- while (time_before(jiffies, timeout)) {
- int ret;
-
- ret = REG_READ(reg, offset);
- if (!(ret & mask))
- return 0;
-
- usleep_range(1000, 2000);
- }
- return -ETIMEDOUT;
-}
-
-static inline int mv88e6352_phy_wait(struct dsa_switch *ds)
-{
- return mv88e6352_wait(ds, REG_GLOBAL2, 0x18, 0x8000);
-}
-
-static inline int mv88e6352_eeprom_load_wait(struct dsa_switch *ds)
-{
- return mv88e6352_wait(ds, REG_GLOBAL2, 0x14, 0x0800);
-}
-
-static inline int mv88e6352_eeprom_busy_wait(struct dsa_switch *ds)
-{
- return mv88e6352_wait(ds, REG_GLOBAL2, 0x14, 0x8000);
-}
-
-static int __mv88e6352_phy_read(struct dsa_switch *ds, int addr, int regnum)
-{
- int ret;
-
- REG_WRITE(REG_GLOBAL2, 0x18, 0x9800 | (addr << 5) | regnum);
-
- ret = mv88e6352_phy_wait(ds);
- if (ret < 0)
- return ret;
-
- return REG_READ(REG_GLOBAL2, 0x19);
-}
-
-static int __mv88e6352_phy_write(struct dsa_switch *ds, int addr, int regnum,
- u16 val)
-{
- REG_WRITE(REG_GLOBAL2, 0x19, val);
- REG_WRITE(REG_GLOBAL2, 0x18, 0x9400 | (addr << 5) | regnum);
-
- return mv88e6352_phy_wait(ds);
-}
-
static char *mv88e6352_probe(struct device *host_dev, int sw_addr)
{
struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev);
@@ -346,12 +293,12 @@ static int mv88e6352_phy_page_read(struct dsa_switch *ds,
int ret;
mutex_lock(&ps->phy_mutex);
- ret = __mv88e6352_phy_write(ds, port, 0x16, page);
+ ret = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
if (ret < 0)
goto error;
- ret = __mv88e6352_phy_read(ds, port, reg);
+ ret = mv88e6xxx_phy_read_indirect(ds, port, reg);
error:
- __mv88e6352_phy_write(ds, port, 0x16, 0x0);
+ mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
mutex_unlock(&ps->phy_mutex);
return ret;
}
@@ -363,13 +310,13 @@ static int mv88e6352_phy_page_write(struct dsa_switch *ds,
int ret;
mutex_lock(&ps->phy_mutex);
- ret = __mv88e6352_phy_write(ds, port, 0x16, page);
+ ret = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
if (ret < 0)
goto error;
- ret = __mv88e6352_phy_write(ds, port, reg, val);
+ ret = mv88e6xxx_phy_write_indirect(ds, port, reg, val);
error:
- __mv88e6352_phy_write(ds, port, 0x16, 0x0);
+ mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
mutex_unlock(&ps->phy_mutex);
return ret;
}
@@ -482,7 +429,7 @@ mv88e6352_phy_read(struct dsa_switch *ds, int port, int regnum)
return addr;
mutex_lock(&ps->phy_mutex);
- ret = __mv88e6352_phy_read(ds, addr, regnum);
+ ret = mv88e6xxx_phy_read_indirect(ds, addr, regnum);
mutex_unlock(&ps->phy_mutex);
return ret;
@@ -499,7 +446,7 @@ mv88e6352_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
return addr;
mutex_lock(&ps->phy_mutex);
- ret = __mv88e6352_phy_write(ds, addr, regnum, val);
+ ret = mv88e6xxx_phy_write_indirect(ds, addr, regnum, val);
mutex_unlock(&ps->phy_mutex);
return ret;
@@ -553,7 +500,7 @@ static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr)
if (ret < 0)
goto error;
- ret = mv88e6352_eeprom_busy_wait(ds);
+ ret = mv88e6xxx_eeprom_busy_wait(ds);
if (ret < 0)
goto error;
@@ -576,7 +523,7 @@ static int mv88e6352_get_eeprom(struct dsa_switch *ds,
eeprom->magic = 0xc3ec4951;
- ret = mv88e6352_eeprom_load_wait(ds);
+ ret = mv88e6xxx_eeprom_load_wait(ds);
if (ret < 0)
return ret;
@@ -657,7 +604,7 @@ static int mv88e6352_write_eeprom_word(struct dsa_switch *ds, int addr,
if (ret < 0)
goto error;
- ret = mv88e6352_eeprom_busy_wait(ds);
+ ret = mv88e6xxx_eeprom_busy_wait(ds);
error:
mutex_unlock(&ps->eeprom_mutex);
return ret;
@@ -681,7 +628,7 @@ static int mv88e6352_set_eeprom(struct dsa_switch *ds,
len = eeprom->len;
eeprom->len = 0;
- ret = mv88e6352_eeprom_load_wait(ds);
+ ret = mv88e6xxx_eeprom_load_wait(ds);
if (ret < 0)
return ret;
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 3e7e31a6abb7..a83ace0803e7 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -596,6 +596,59 @@ error:
}
#endif /* CONFIG_NET_DSA_HWMON */
+static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
+{
+ unsigned long timeout = jiffies + HZ / 10;
+
+ while (time_before(jiffies, timeout)) {
+ int ret;
+
+ ret = REG_READ(reg, offset);
+ if (!(ret & mask))
+ return 0;
+
+ usleep_range(1000, 2000);
+ }
+ return -ETIMEDOUT;
+}
+
+int mv88e6xxx_phy_wait(struct dsa_switch *ds)
+{
+ return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x18, 0x8000);
+}
+
+int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
+{
+ return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x14, 0x0800);
+}
+
+int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
+{
+ return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x14, 0x8000);
+}
+
+int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum)
+{
+ int ret;
+
+ REG_WRITE(REG_GLOBAL2, 0x18, 0x9800 | (addr << 5) | regnum);
+
+ ret = mv88e6xxx_phy_wait(ds);
+ if (ret < 0)
+ return ret;
+
+ return REG_READ(REG_GLOBAL2, 0x19);
+}
+
+int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum,
+ u16 val)
+{
+ REG_WRITE(REG_GLOBAL2, 0x19, val);
+ REG_WRITE(REG_GLOBAL2, 0x18, 0x9400 | (addr << 5) | regnum);
+
+ return mv88e6xxx_phy_wait(ds);
+}
+
static int __init mv88e6xxx_init(void)
{
#if IS_ENABLED(CONFIG_NET_DSA_MV88E6131)
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 03e397efde36..72942271bb67 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -82,6 +82,12 @@ int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port);
void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
struct ethtool_regs *regs, void *_p);
int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp);
+int mv88e6xxx_phy_wait(struct dsa_switch *ds);
+int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds);
+int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds);
+int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum);
+int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum,
+ u16 val);
extern struct dsa_switch_driver mv88e6131_switch_driver;
extern struct dsa_switch_driver mv88e6123_61_65_switch_driver;
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
index 760c72c6e2ac..a1ee261bff5c 100644
--- a/drivers/net/ethernet/altera/altera_tse_main.c
+++ b/drivers/net/ethernet/altera/altera_tse_main.c
@@ -105,11 +105,11 @@ static int altera_tse_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
/* set MDIO address */
csrwr32((mii_id & 0x1f), priv->mac_dev,
- tse_csroffs(mdio_phy0_addr));
+ tse_csroffs(mdio_phy1_addr));
/* get the data */
return csrrd32(priv->mac_dev,
- tse_csroffs(mdio_phy0) + regnum * 4) & 0xffff;
+ tse_csroffs(mdio_phy1) + regnum * 4) & 0xffff;
}
static int altera_tse_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
@@ -120,10 +120,10 @@ static int altera_tse_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
/* set MDIO address */
csrwr32((mii_id & 0x1f), priv->mac_dev,
- tse_csroffs(mdio_phy0_addr));
+ tse_csroffs(mdio_phy1_addr));
/* write the data */
- csrwr32(value, priv->mac_dev, tse_csroffs(mdio_phy0) + regnum * 4);
+ csrwr32(value, priv->mac_dev, tse_csroffs(mdio_phy1) + regnum * 4);
return 0;
}
@@ -1099,8 +1099,12 @@ static int tse_open(struct net_device *dev)
spin_lock(&priv->mac_cfg_lock);
ret = reset_mac(priv);
+ /* Note that reset_mac will fail if the clocks are gated by the PHY
+ * due to the PHY being put into isolation or power down mode.
+ * This is not an error if reset fails due to no clock.
+ */
if (ret)
- netdev_err(dev, "Cannot reset MAC core (error: %d)\n", ret);
+ netdev_dbg(dev, "Cannot reset MAC core (error: %d)\n", ret);
ret = init_mac(priv);
spin_unlock(&priv->mac_cfg_lock);
@@ -1204,8 +1208,12 @@ static int tse_shutdown(struct net_device *dev)
spin_lock(&priv->tx_lock);
ret = reset_mac(priv);
+ /* Note that reset_mac will fail if the clocks are gated by the PHY
+ * due to the PHY being put into isolation or power down mode.
+ * This is not an error if reset fails due to no clock.
+ */
if (ret)
- netdev_err(dev, "Cannot reset MAC core (error: %d)\n", ret);
+ netdev_dbg(dev, "Cannot reset MAC core (error: %d)\n", ret);
priv->dmaops->reset_dma(priv);
free_skbufs(dev);
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 41a3c9804427..ee4fdfe65e9e 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -71,12 +71,12 @@ config BCMGENET
Broadcom BCM7xxx Set Top Box family chipset.
config BNX2
- tristate "QLogic NetXtremeII support"
+ tristate "QLogic bnx2 support"
depends on PCI
select CRC32
select FW_LOADER
---help---
- This driver supports QLogic NetXtremeII gigabit Ethernet cards.
+ This driver supports QLogic bnx2 gigabit Ethernet cards.
To compile this driver as a module, choose M here: the module
will be called bnx2. This is recommended.
@@ -87,8 +87,8 @@ config CNIC
select BNX2
select UIO
---help---
- This driver supports offload features of QLogic NetXtremeII
- gigabit Ethernet cards.
+ This driver supports offload features of QLogic bnx2 gigabit
+ Ethernet cards.
To compile this driver as a module, choose M here: the module
will be called cnic. This is recommended.
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 02bf0b86995b..9f146b990c01 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -1,7 +1,7 @@
-/* bnx2.c: QLogic NX2 network driver.
+/* bnx2.c: QLogic bnx2 network driver.
*
* Copyright (c) 2004-2014 Broadcom Corporation
- * Copyright (c) 2014 QLogic Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -58,8 +58,8 @@
#include "bnx2_fw.h"
#define DRV_MODULE_NAME "bnx2"
-#define DRV_MODULE_VERSION "2.2.5"
-#define DRV_MODULE_RELDATE "December 20, 2013"
+#define DRV_MODULE_VERSION "2.2.6"
+#define DRV_MODULE_RELDATE "January 29, 2014"
#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-6.2.3.fw"
#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-6.0.15.fw"
#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-6.2.1b.fw"
@@ -72,10 +72,10 @@
#define TX_TIMEOUT (5*HZ)
static char version[] =
- "QLogic NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+ "QLogic " DRV_MODULE_NAME " Gigabit Ethernet Driver v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
-MODULE_DESCRIPTION("QLogic NetXtreme II BCM5706/5708/5709/5716 Driver");
+MODULE_DESCRIPTION("QLogic BCM5706/5708/5709/5716 Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
MODULE_FIRMWARE(FW_MIPS_FILE_06);
@@ -4984,8 +4984,6 @@ bnx2_init_chip(struct bnx2 *bp)
bp->idle_chk_status_idx = 0xffff;
- bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
-
/* Set up how to generate a link change interrupt. */
BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
diff --git a/drivers/net/ethernet/broadcom/bnx2.h b/drivers/net/ethernet/broadcom/bnx2.h
index 28df35d35893..f92f76c44756 100644
--- a/drivers/net/ethernet/broadcom/bnx2.h
+++ b/drivers/net/ethernet/broadcom/bnx2.h
@@ -1,7 +1,7 @@
-/* bnx2.h: QLogic NX2 network driver.
+/* bnx2.h: QLogic bnx2 network driver.
*
* Copyright (c) 2004-2014 Broadcom Corporation
- * Copyright (c) 2014 QLogic Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/net/ethernet/broadcom/bnx2_fw.h b/drivers/net/ethernet/broadcom/bnx2_fw.h
index 7db79c28b5ff..b0f2ccadaffd 100644
--- a/drivers/net/ethernet/broadcom/bnx2_fw.h
+++ b/drivers/net/ethernet/broadcom/bnx2_fw.h
@@ -1,7 +1,7 @@
-/* bnx2_fw.h: QLogic NX2 network driver.
+/* bnx2_fw.h: QLogic bnx2 network driver.
*
* Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation
- * Copyright (c) 2014 QLogic Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index f05fab65d78a..17c145fdf3ff 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -1,7 +1,7 @@
/* cnic.c: QLogic CNIC core network driver.
*
* Copyright (c) 2006-2014 Broadcom Corporation
- * Copyright (c) 2014 QLogic Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -58,11 +58,11 @@
#define CNIC_MODULE_NAME "cnic"
static char version[] =
- "QLogic NetXtreme II CNIC Driver " CNIC_MODULE_NAME " v" CNIC_MODULE_VERSION " (" CNIC_MODULE_RELDATE ")\n";
+ "QLogic " CNIC_MODULE_NAME "Driver v" CNIC_MODULE_VERSION " (" CNIC_MODULE_RELDATE ")\n";
MODULE_AUTHOR("Michael Chan <mchan@broadcom.com> and John(Zongxi) "
"Chen (zongxi@broadcom.com");
-MODULE_DESCRIPTION("QLogic NetXtreme II CNIC Driver");
+MODULE_DESCRIPTION("QLogic cnic Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(CNIC_MODULE_VERSION);
diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h
index 8bb36c1c4d68..ef6125b0ee3e 100644
--- a/drivers/net/ethernet/broadcom/cnic_if.h
+++ b/drivers/net/ethernet/broadcom/cnic_if.h
@@ -1,7 +1,7 @@
-/* cnic_if.h: QLogic CNIC core network driver.
+/* cnic_if.h: QLogic cnic core network driver.
*
* Copyright (c) 2006-2014 Broadcom Corporation
- * Copyright (c) 2014 QLogic Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,8 +15,8 @@
#include "bnx2x/bnx2x_mfw_req.h"
-#define CNIC_MODULE_VERSION "2.5.20"
-#define CNIC_MODULE_RELDATE "March 14, 2014"
+#define CNIC_MODULE_VERSION "2.5.21"
+#define CNIC_MODULE_RELDATE "January 29, 2015"
#define CNIC_ULP_RDMA 0
#define CNIC_ULP_ISCSI 1
diff --git a/drivers/net/ethernet/brocade/Kconfig b/drivers/net/ethernet/brocade/Kconfig
index 264155778857..4e8c0b6c57d0 100644
--- a/drivers/net/ethernet/brocade/Kconfig
+++ b/drivers/net/ethernet/brocade/Kconfig
@@ -1,9 +1,9 @@
#
-# Brocade device configuration
+# QLogic BR-series device configuration
#
config NET_VENDOR_BROCADE
- bool "Brocade devices"
+ bool "QLogic BR-series devices"
default y
depends on PCI
---help---
@@ -13,8 +13,8 @@ config NET_VENDOR_BROCADE
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
- the questions about Brocade cards. If you say Y, you will be asked for
- your specific card in the following questions.
+ the questions about QLogic BR-series cards. If you say Y, you will be
+ asked for your specific card in the following questions.
if NET_VENDOR_BROCADE
diff --git a/drivers/net/ethernet/brocade/Makefile b/drivers/net/ethernet/brocade/Makefile
index b58238d2df6a..fec10f9b4558 100644
--- a/drivers/net/ethernet/brocade/Makefile
+++ b/drivers/net/ethernet/brocade/Makefile
@@ -1,5 +1,5 @@
#
-# Makefile for the Brocade device drivers.
+# Makefile for the QLogic BR-series device drivers.
#
obj-$(CONFIG_BNA) += bna/
diff --git a/drivers/net/ethernet/brocade/bna/Kconfig b/drivers/net/ethernet/brocade/bna/Kconfig
index dc2eb526fbf7..fe01279a8843 100644
--- a/drivers/net/ethernet/brocade/bna/Kconfig
+++ b/drivers/net/ethernet/brocade/bna/Kconfig
@@ -1,17 +1,17 @@
#
-# Brocade network device configuration
+# QLogic BR-series network device configuration
#
config BNA
- tristate "Brocade 1010/1020 10Gb Ethernet Driver support"
+ tristate "QLogic BR-series 1010/1020/1860 10Gb Ethernet Driver support"
depends on PCI
---help---
- This driver supports Brocade 1010/1020 10Gb CEE capable Ethernet
- cards.
+ This driver supports QLogic BR-series 1010/1020/1860 10Gb CEE capable
+ Ethernet cards.
To compile this driver as a module, choose M here: the module
will be called bna.
- For general information and support, go to the Brocade support
+ For general information and support, go to the QLogic support
website at:
- <http://support.brocade.com>
+ <http://support.qlogic.com>
diff --git a/drivers/net/ethernet/brocade/bna/Makefile b/drivers/net/ethernet/brocade/bna/Makefile
index 6027302ae73a..6e10b99733a2 100644
--- a/drivers/net/ethernet/brocade/bna/Makefile
+++ b/drivers/net/ethernet/brocade/bna/Makefile
@@ -1,5 +1,6 @@
#
-# Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+# Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+# Copyright (c) 2014-2015 QLogic Corporation.
# All rights reserved.
#
diff --git a/drivers/net/ethernet/brocade/bna/bfa_cee.c b/drivers/net/ethernet/brocade/bna/bfa_cee.c
index 550d2521ba76..cf9f3956f198 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_cee.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_cee.c
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#include "bfa_cee.h"
diff --git a/drivers/net/ethernet/brocade/bna/bfa_cee.h b/drivers/net/ethernet/brocade/bna/bfa_cee.h
index 93fde633d6f3..d04eef5d5a77 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_cee.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_cee.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BFA_CEE_H__
diff --git a/drivers/net/ethernet/brocade/bna/bfa_cs.h b/drivers/net/ethernet/brocade/bna/bfa_cs.h
index ad004a4c3897..af25d8e8fae0 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_cs.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_cs.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
/* BFA common services */
diff --git a/drivers/net/ethernet/brocade/bna/bfa_defs.h b/drivers/net/ethernet/brocade/bna/bfa_defs.h
index b7d8127c198f..3bfd9da92630 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_defs.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BFA_DEFS_H__
diff --git a/drivers/net/ethernet/brocade/bna/bfa_defs_cna.h b/drivers/net/ethernet/brocade/bna/bfa_defs_cna.h
index b39c5f23974b..63e300f5ba41 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_defs_cna.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs_cna.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BFA_DEFS_CNA_H__
#define __BFA_DEFS_CNA_H__
diff --git a/drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h b/drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h
index 7fb396fe679d..7a45cd0b594d 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs_mfg_comm.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BFA_DEFS_MFG_COMM_H__
#define __BFA_DEFS_MFG_COMM_H__
diff --git a/drivers/net/ethernet/brocade/bna/bfa_defs_status.h b/drivers/net/ethernet/brocade/bna/bfa_defs_status.h
index ea9af9ae754d..a43b56002752 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_defs_status.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs_status.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BFA_DEFS_STATUS_H__
#define __BFA_DEFS_STATUS_H__
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
index 354ae9792bad..f2d13238b02e 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#include "bfa_ioc.h"
@@ -2763,7 +2764,7 @@ bfa_nw_ioc_notify_register(struct bfa_ioc *ioc,
list_add_tail(&notify->qe, &ioc->notify_q);
}
-#define BFA_MFG_NAME "Brocade"
+#define BFA_MFG_NAME "QLogic"
static void
bfa_ioc_get_adapter_attr(struct bfa_ioc *ioc,
struct bfa_adapter_attr *ad_attr)
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.h b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
index 20cff7df4b55..effb7156e7a4 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BFA_IOC_H__
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c b/drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c
index d639558455cb..66c8507d7717 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#include "bfa_ioc.h"
diff --git a/drivers/net/ethernet/brocade/bna/bfa_msgq.c b/drivers/net/ethernet/brocade/bna/bfa_msgq.c
index 55067d0d25cf..c07d5b9372f4 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_msgq.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_msgq.c
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
/* MSGQ module source file. */
diff --git a/drivers/net/ethernet/brocade/bna/bfa_msgq.h b/drivers/net/ethernet/brocade/bna/bfa_msgq.h
index a6a565a366dc..66bc8b5acd57 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_msgq.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_msgq.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BFA_MSGQ_H__
diff --git a/drivers/net/ethernet/brocade/bna/bfi.h b/drivers/net/ethernet/brocade/bna/bfi.h
index 8c563a77cdf6..f1e1129e6241 100644
--- a/drivers/net/ethernet/brocade/bna/bfi.h
+++ b/drivers/net/ethernet/brocade/bna/bfi.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BFI_H__
#define __BFI_H__
diff --git a/drivers/net/ethernet/brocade/bna/bfi_cna.h b/drivers/net/ethernet/brocade/bna/bfi_cna.h
index 6704a4392973..bd605bee72ee 100644
--- a/drivers/net/ethernet/brocade/bna/bfi_cna.h
+++ b/drivers/net/ethernet/brocade/bna/bfi_cna.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BFI_CNA_H__
#define __BFI_CNA_H__
diff --git a/drivers/net/ethernet/brocade/bna/bfi_enet.h b/drivers/net/ethernet/brocade/bna/bfi_enet.h
index ae072dc5d238..bccca3bbadb8 100644
--- a/drivers/net/ethernet/brocade/bna/bfi_enet.h
+++ b/drivers/net/ethernet/brocade/bna/bfi_enet.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
/* BNA Hardware and Firmware Interface */
diff --git a/drivers/net/ethernet/brocade/bna/bfi_reg.h b/drivers/net/ethernet/brocade/bna/bfi_reg.h
index c49fa312ddbd..2835b51eabec 100644
--- a/drivers/net/ethernet/brocade/bna/bfi_reg.h
+++ b/drivers/net/ethernet/brocade/bna/bfi_reg.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,13 +11,14 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
/*
- * bfi_reg.h ASIC register defines for all Brocade adapter ASICs
+ * bfi_reg.h ASIC register defines for all QLogic BR-series adapter ASICs
*/
#ifndef __BFI_REG_H__
@@ -221,7 +222,7 @@ enum {
#define __PMM_1T_RESET_P 0x00000001
#define PMM_1T_RESET_REG_P1 0x00023c1c
-/* Brocade 1860 Adapter specific defines */
+/* QLogic BR-series 1860 Adapter specific defines */
#define CT2_PCI_CPQ_BASE 0x00030000
#define CT2_PCI_APP_BASE 0x00030100
#define CT2_PCI_ETH_BASE 0x00030400
@@ -264,7 +265,7 @@ enum {
#define CT2_HOSTFN_MSIX_VT_INDEX_MBOX_ERR (CT2_PCI_APP_BASE + 0x38)
/*
- * Brocade 1860 adapter CPQ block registers
+ * QLogic BR-series 1860 adapter CPQ block registers
*/
#define CT2_HOSTFN_LPU0_MBOX0 (CT2_PCI_CPQ_BASE + 0x00)
#define CT2_HOSTFN_LPU1_MBOX0 (CT2_PCI_CPQ_BASE + 0x20)
diff --git a/drivers/net/ethernet/brocade/bna/bna.h b/drivers/net/ethernet/brocade/bna/bna.h
index 1f512190d696..8ba72b1f36d9 100644
--- a/drivers/net/ethernet/brocade/bna/bna.h
+++ b/drivers/net/ethernet/brocade/bna/bna.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BNA_H__
#define __BNA_H__
diff --git a/drivers/net/ethernet/brocade/bna/bna_enet.c b/drivers/net/ethernet/brocade/bna/bna_enet.c
index 903466ef41c0..deb8da6ab9cc 100644
--- a/drivers/net/ethernet/brocade/bna/bna_enet.c
+++ b/drivers/net/ethernet/brocade/bna/bna_enet.c
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#include "bna.h"
diff --git a/drivers/net/ethernet/brocade/bna/bna_hw_defs.h b/drivers/net/ethernet/brocade/bna/bna_hw_defs.h
index 2702d02e98d9..c5feab130d6d 100644
--- a/drivers/net/ethernet/brocade/bna/bna_hw_defs.h
+++ b/drivers/net/ethernet/brocade/bna/bna_hw_defs.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
/* File for interrupt macros and functions */
diff --git a/drivers/net/ethernet/brocade/bna/bna_tx_rx.c b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
index 5fac411c52f4..8ab3a5f62706 100644
--- a/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
+++ b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#include "bna.h"
#include "bfi.h"
diff --git a/drivers/net/ethernet/brocade/bna/bna_types.h b/drivers/net/ethernet/brocade/bna/bna_types.h
index 621547cd3504..d0a7a566f5d6 100644
--- a/drivers/net/ethernet/brocade/bna/bna_types.h
+++ b/drivers/net/ethernet/brocade/bna/bna_types.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BNA_TYPES_H__
#define __BNA_TYPES_H__
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index 7714d7790089..37072a83f9d6 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#include <linux/bitops.h>
#include <linux/netdevice.h>
@@ -3867,7 +3868,7 @@ bnad_module_init(void)
{
int err;
- pr_info("Brocade 10G Ethernet driver - version: %s\n",
+ pr_info("QLogic BR-series 10G Ethernet driver - version: %s\n",
BNAD_VERSION);
bfa_nw_ioc_auto_recover(bnad_ioc_auto_recover);
@@ -3894,7 +3895,7 @@ module_exit(bnad_module_exit);
MODULE_AUTHOR("Brocade");
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Brocade 10G PCIe Ethernet driver");
+MODULE_DESCRIPTION("QLogic BR-series 10G PCIe Ethernet driver");
MODULE_VERSION(BNAD_VERSION);
MODULE_FIRMWARE(CNA_FW_FILE_CT);
MODULE_FIRMWARE(CNA_FW_FILE_CT2);
diff --git a/drivers/net/ethernet/brocade/bna/bnad.h b/drivers/net/ethernet/brocade/bna/bnad.h
index 2842c188e0da..7ead6c23edb6 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.h
+++ b/drivers/net/ethernet/brocade/bna/bnad.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __BNAD_H__
#define __BNAD_H__
@@ -71,7 +72,7 @@ struct bnad_rx_ctrl {
#define BNAD_NAME "bna"
#define BNAD_NAME_LEN 64
-#define BNAD_VERSION "3.2.23.0"
+#define BNAD_VERSION "3.2.25.1"
#define BNAD_MAILBOX_MSIX_INDEX 0
#define BNAD_MAILBOX_MSIX_VECTORS 1
diff --git a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
index 619083a860a4..72c89550417c 100644
--- a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
+++ b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#include <linux/debugfs.h>
diff --git a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
index d26adac6ab99..12f344debd1c 100644
--- a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
+++ b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#include "cna.h"
diff --git a/drivers/net/ethernet/brocade/bna/cna.h b/drivers/net/ethernet/brocade/bna/cna.h
index b3ff6d507951..28e7d0ffeab1 100644
--- a/drivers/net/ethernet/brocade/bna/cna.h
+++ b/drivers/net/ethernet/brocade/bna/cna.h
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2006-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2006-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#ifndef __CNA_H__
@@ -37,8 +38,8 @@
extern char bfa_version[];
-#define CNA_FW_FILE_CT "ctfw-3.2.3.0.bin"
-#define CNA_FW_FILE_CT2 "ct2fw-3.2.3.0.bin"
+#define CNA_FW_FILE_CT "ctfw-3.2.5.1.bin"
+#define CNA_FW_FILE_CT2 "ct2fw-3.2.5.1.bin"
#define FC_SYMNAME_MAX 256 /*!< max name server symbolic name size */
#pragma pack(1)
diff --git a/drivers/net/ethernet/brocade/bna/cna_fwimg.c b/drivers/net/ethernet/brocade/bna/cna_fwimg.c
index 6f72771caea6..ebf462d8082f 100644
--- a/drivers/net/ethernet/brocade/bna/cna_fwimg.c
+++ b/drivers/net/ethernet/brocade/bna/cna_fwimg.c
@@ -1,5 +1,5 @@
/*
- * Linux network driver for Brocade Converged Network Adapter.
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -11,9 +11,10 @@
* General Public License for more details.
*/
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*/
#include <linux/firmware.h>
#include "bnad.h"
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index ad76b8e35a00..05fb36da0cff 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -449,7 +449,7 @@ static void macb_update_stats(struct macb *bp)
WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4);
for(; p < end; p++, reg++)
- *p += __raw_readl(reg);
+ *p += readl_relaxed(reg);
}
static int macb_halt_tx(struct macb *bp)
@@ -1585,7 +1585,11 @@ static void macb_configure_dma(struct macb *bp)
if (bp->dma_burst_length)
dmacfg = GEM_BFINS(FBLDO, bp->dma_burst_length, dmacfg);
dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
- dmacfg &= ~GEM_BIT(ENDIA);
+ dmacfg &= ~GEM_BIT(ENDIA_PKT);
+ /* Tell the chip to byteswap descriptors on big-endian hosts */
+#ifdef __BIG_ENDIAN
+ dmacfg |= GEM_BIT(ENDIA_DESC);
+#endif
if (bp->dev->features & NETIF_F_HW_CSUM)
dmacfg |= GEM_BIT(TXCOEN);
else
@@ -1832,14 +1836,14 @@ static void gem_update_stats(struct macb *bp)
for (i = 0; i < GEM_STATS_LEN; ++i, ++p) {
u32 offset = gem_statistics[i].offset;
- u64 val = __raw_readl(bp->regs + offset);
+ u64 val = readl_relaxed(bp->regs + offset);
bp->ethtool_stats[i] += val;
*p += val;
if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) {
/* Add GEM_OCTTXH, GEM_OCTRXH */
- val = __raw_readl(bp->regs + offset + 4);
+ val = readl_relaxed(bp->regs + offset + 4);
bp->ethtool_stats[i] += ((u64)val) << 32;
*(++p) += val;
}
@@ -2191,12 +2195,14 @@ static void macb_probe_queues(void __iomem *mem,
*num_queues = 1;
/* is it macb or gem ? */
- mid = __raw_readl(mem + MACB_MID);
+ mid = readl_relaxed(mem + MACB_MID);
+
if (MACB_BFEXT(IDNUM, mid) != 0x2)
return;
/* bit 0 is never set but queue 0 always exists */
- *queue_mask = __raw_readl(mem + GEM_DCFG6) & 0xff;
+ *queue_mask = readl_relaxed(mem + GEM_DCFG6) & 0xff;
+
*queue_mask |= 0x1;
for (hw_q = 1; hw_q < MACB_MAX_QUEUES; ++hw_q)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 31dc080f2437..57f0a1a7415d 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -229,7 +229,8 @@
/* Bitfields in DMACFG. */
#define GEM_FBLDO_OFFSET 0 /* fixed burst length for DMA */
#define GEM_FBLDO_SIZE 5
-#define GEM_ENDIA_OFFSET 7 /* endian swap mode for packet data access */
+#define GEM_ENDIA_DESC_OFFSET 6 /* endian swap mode for management descriptor access */
+#define GEM_ENDIA_PKT_OFFSET 7 /* endian swap mode for packet data access */
#define GEM_ENDIA_SIZE 1
#define GEM_RXBMS_OFFSET 8 /* RX packet buffer memory size select */
#define GEM_RXBMS_SIZE 2
@@ -423,17 +424,17 @@
/* Register access macros */
#define macb_readl(port,reg) \
- __raw_readl((port)->regs + MACB_##reg)
+ readl_relaxed((port)->regs + MACB_##reg)
#define macb_writel(port,reg,value) \
- __raw_writel((value), (port)->regs + MACB_##reg)
+ writel_relaxed((value), (port)->regs + MACB_##reg)
#define gem_readl(port, reg) \
- __raw_readl((port)->regs + GEM_##reg)
+ readl_relaxed((port)->regs + GEM_##reg)
#define gem_writel(port, reg, value) \
- __raw_writel((value), (port)->regs + GEM_##reg)
+ writel_relaxed((value), (port)->regs + GEM_##reg)
#define queue_readl(queue, reg) \
- __raw_readl((queue)->bp->regs + (queue)->reg)
+ readl_relaxed((queue)->bp->regs + (queue)->reg)
#define queue_writel(queue, reg, value) \
- __raw_writel((value), (queue)->bp->regs + (queue)->reg)
+ writel_relaxed((value), (queue)->bp->regs + (queue)->reg)
/* Conditional GEM/MACB macros. These perform the operation to the correct
* register dependent on whether the device is a GEM or a MACB. For registers
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 27de37aa90af..ad33bf1f1df1 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -238,10 +238,17 @@ struct be_tx_stats {
struct u64_stats_sync sync_compl;
};
+/* Structure to hold some data of interest obtained from a TX CQE */
+struct be_tx_compl_info {
+ u8 status; /* Completion status */
+ u16 end_index; /* Completed TXQ Index */
+};
+
struct be_tx_obj {
u32 db_offset;
struct be_queue_info q;
struct be_queue_info cq;
+ struct be_tx_compl_info txcp;
/* Remember the skbs that were transmitted */
struct sk_buff *sent_skb_list[TX_Q_LEN];
struct be_tx_stats stats;
@@ -417,6 +424,39 @@ struct rss_info {
u8 rss_hkey[RSS_HASH_KEY_LEN];
};
+/* Macros to read/write the 'features' word of be_wrb_params structure.
+ */
+#define BE_WRB_F_BIT(name) BE_WRB_F_##name##_BIT
+#define BE_WRB_F_MASK(name) BIT_MASK(BE_WRB_F_##name##_BIT)
+
+#define BE_WRB_F_GET(word, name) \
+ (((word) & (BE_WRB_F_MASK(name))) >> BE_WRB_F_BIT(name))
+
+#define BE_WRB_F_SET(word, name, val) \
+ ((word) |= (((val) << BE_WRB_F_BIT(name)) & BE_WRB_F_MASK(name)))
+
+/* Feature/offload bits */
+enum {
+ BE_WRB_F_CRC_BIT, /* Ethernet CRC */
+ BE_WRB_F_IPCS_BIT, /* IP csum */
+ BE_WRB_F_TCPCS_BIT, /* TCP csum */
+ BE_WRB_F_UDPCS_BIT, /* UDP csum */
+ BE_WRB_F_LSO_BIT, /* LSO */
+ BE_WRB_F_LSO6_BIT, /* LSO6 */
+ BE_WRB_F_VLAN_BIT, /* VLAN */
+ BE_WRB_F_VLAN_SKIP_HW_BIT /* Skip VLAN tag (workaround) */
+};
+
+/* The structure below provides a HW-agnostic abstraction of WRB params
+ * retrieved from a TX skb. This is in turn passed to chip specific routines
+ * during transmit, to set the corresponding params in the WRB.
+ */
+struct be_wrb_params {
+ u32 features; /* Feature bits */
+ u16 vlan_tag; /* VLAN tag */
+ u16 lso_mss; /* MSS for LSO */
+};
+
struct be_adapter {
struct pci_dev *pdev;
struct net_device *netdev;
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 0a816859aca5..c1553fba7916 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -727,48 +727,86 @@ static u16 skb_ip_proto(struct sk_buff *skb)
ip_hdr(skb)->protocol : ipv6_hdr(skb)->nexthdr;
}
-static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
- struct sk_buff *skb, u32 wrb_cnt, u32 len,
- bool skip_hw_vlan)
+static inline bool be_is_txq_full(struct be_tx_obj *txo)
{
- u16 vlan_tag, proto;
+ return atomic_read(&txo->q.used) + BE_MAX_TX_FRAG_COUNT >= txo->q.len;
+}
- memset(hdr, 0, sizeof(*hdr));
+static inline bool be_can_txq_wake(struct be_tx_obj *txo)
+{
+ return atomic_read(&txo->q.used) < txo->q.len / 2;
+}
- SET_TX_WRB_HDR_BITS(crc, hdr, 1);
+static inline bool be_is_tx_compl_pending(struct be_tx_obj *txo)
+{
+ return atomic_read(&txo->q.used) > txo->pend_wrb_cnt;
+}
+
+static void be_get_wrb_params_from_skb(struct be_adapter *adapter,
+ struct sk_buff *skb,
+ struct be_wrb_params *wrb_params)
+{
+ u16 proto;
if (skb_is_gso(skb)) {
- SET_TX_WRB_HDR_BITS(lso, hdr, 1);
- SET_TX_WRB_HDR_BITS(lso_mss, hdr, skb_shinfo(skb)->gso_size);
+ BE_WRB_F_SET(wrb_params->features, LSO, 1);
+ wrb_params->lso_mss = skb_shinfo(skb)->gso_size;
if (skb_is_gso_v6(skb) && !lancer_chip(adapter))
- SET_TX_WRB_HDR_BITS(lso6, hdr, 1);
+ BE_WRB_F_SET(wrb_params->features, LSO6, 1);
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (skb->encapsulation) {
- SET_TX_WRB_HDR_BITS(ipcs, hdr, 1);
+ BE_WRB_F_SET(wrb_params->features, IPCS, 1);
proto = skb_inner_ip_proto(skb);
} else {
proto = skb_ip_proto(skb);
}
if (proto == IPPROTO_TCP)
- SET_TX_WRB_HDR_BITS(tcpcs, hdr, 1);
+ BE_WRB_F_SET(wrb_params->features, TCPCS, 1);
else if (proto == IPPROTO_UDP)
- SET_TX_WRB_HDR_BITS(udpcs, hdr, 1);
+ BE_WRB_F_SET(wrb_params->features, UDPCS, 1);
}
if (skb_vlan_tag_present(skb)) {
- SET_TX_WRB_HDR_BITS(vlan, hdr, 1);
- vlan_tag = be_get_tx_vlan_tag(adapter, skb);
- SET_TX_WRB_HDR_BITS(vlan_tag, hdr, vlan_tag);
+ BE_WRB_F_SET(wrb_params->features, VLAN, 1);
+ wrb_params->vlan_tag = be_get_tx_vlan_tag(adapter, skb);
}
- SET_TX_WRB_HDR_BITS(num_wrb, hdr, wrb_cnt);
- SET_TX_WRB_HDR_BITS(len, hdr, len);
+ BE_WRB_F_SET(wrb_params->features, CRC, 1);
+}
+
+static void wrb_fill_hdr(struct be_adapter *adapter,
+ struct be_eth_hdr_wrb *hdr,
+ struct be_wrb_params *wrb_params,
+ struct sk_buff *skb)
+{
+ memset(hdr, 0, sizeof(*hdr));
- /* Hack to skip HW VLAN tagging needs evt = 1, compl = 0
- * When this hack is not needed, the evt bit is set while ringing DB
+ SET_TX_WRB_HDR_BITS(crc, hdr,
+ BE_WRB_F_GET(wrb_params->features, CRC));
+ SET_TX_WRB_HDR_BITS(ipcs, hdr,
+ BE_WRB_F_GET(wrb_params->features, IPCS));
+ SET_TX_WRB_HDR_BITS(tcpcs, hdr,
+ BE_WRB_F_GET(wrb_params->features, TCPCS));
+ SET_TX_WRB_HDR_BITS(udpcs, hdr,
+ BE_WRB_F_GET(wrb_params->features, UDPCS));
+
+ SET_TX_WRB_HDR_BITS(lso, hdr,
+ BE_WRB_F_GET(wrb_params->features, LSO));
+ SET_TX_WRB_HDR_BITS(lso6, hdr,
+ BE_WRB_F_GET(wrb_params->features, LSO6));
+ SET_TX_WRB_HDR_BITS(lso_mss, hdr, wrb_params->lso_mss);
+
+ /* Hack to skip HW VLAN tagging needs evt = 1, compl = 0. When this
+ * hack is not needed, the evt bit is set while ringing DB.
*/
- if (skip_hw_vlan)
- SET_TX_WRB_HDR_BITS(event, hdr, 1);
+ SET_TX_WRB_HDR_BITS(event, hdr,
+ BE_WRB_F_GET(wrb_params->features, VLAN_SKIP_HW));
+ SET_TX_WRB_HDR_BITS(vlan, hdr,
+ BE_WRB_F_GET(wrb_params->features, VLAN));
+ SET_TX_WRB_HDR_BITS(vlan_tag, hdr, wrb_params->vlan_tag);
+
+ SET_TX_WRB_HDR_BITS(num_wrb, hdr, skb_wrb_cnt(skb));
+ SET_TX_WRB_HDR_BITS(len, hdr, skb->len);
}
static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb,
@@ -788,77 +826,124 @@ static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb,
}
}
-/* Returns the number of WRBs used up by the skb */
+/* Grab a WRB header for xmit */
+static u16 be_tx_get_wrb_hdr(struct be_tx_obj *txo)
+{
+ u16 head = txo->q.head;
+
+ queue_head_inc(&txo->q);
+ return head;
+}
+
+/* Set up the WRB header for xmit */
+static void be_tx_setup_wrb_hdr(struct be_adapter *adapter,
+ struct be_tx_obj *txo,
+ struct be_wrb_params *wrb_params,
+ struct sk_buff *skb, u16 head)
+{
+ u32 num_frags = skb_wrb_cnt(skb);
+ struct be_queue_info *txq = &txo->q;
+ struct be_eth_hdr_wrb *hdr = queue_index_node(txq, head);
+
+ wrb_fill_hdr(adapter, hdr, wrb_params, skb);
+ be_dws_cpu_to_le(hdr, sizeof(*hdr));
+
+ BUG_ON(txo->sent_skb_list[head]);
+ txo->sent_skb_list[head] = skb;
+ txo->last_req_hdr = head;
+ atomic_add(num_frags, &txq->used);
+ txo->last_req_wrb_cnt = num_frags;
+ txo->pend_wrb_cnt += num_frags;
+}
+
+/* Setup a WRB fragment (buffer descriptor) for xmit */
+static void be_tx_setup_wrb_frag(struct be_tx_obj *txo, dma_addr_t busaddr,
+ int len)
+{
+ struct be_eth_wrb *wrb;
+ struct be_queue_info *txq = &txo->q;
+
+ wrb = queue_head_node(txq);
+ wrb_fill(wrb, busaddr, len);
+ queue_head_inc(txq);
+}
+
+/* Bring the queue back to the state it was in before be_xmit_enqueue() routine
+ * was invoked. The producer index is restored to the previous packet and the
+ * WRBs of the current packet are unmapped. Invoked to handle tx setup errors.
+ */
+static void be_xmit_restore(struct be_adapter *adapter,
+ struct be_tx_obj *txo, u16 head, bool map_single,
+ u32 copied)
+{
+ struct device *dev;
+ struct be_eth_wrb *wrb;
+ struct be_queue_info *txq = &txo->q;
+
+ dev = &adapter->pdev->dev;
+ txq->head = head;
+
+ /* skip the first wrb (hdr); it's not mapped */
+ queue_head_inc(txq);
+ while (copied) {
+ wrb = queue_head_node(txq);
+ unmap_tx_frag(dev, wrb, map_single);
+ map_single = false;
+ copied -= le32_to_cpu(wrb->frag_len);
+ queue_head_inc(txq);
+ }
+
+ txq->head = head;
+}
+
+/* Enqueue the given packet for transmit. This routine allocates WRBs for the
+ * packet, dma maps the packet buffers and sets up the WRBs. Returns the number
+ * of WRBs used up by the packet.
+ */
static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo,
- struct sk_buff *skb, bool skip_hw_vlan)
+ struct sk_buff *skb,
+ struct be_wrb_params *wrb_params)
{
u32 i, copied = 0, wrb_cnt = skb_wrb_cnt(skb);
struct device *dev = &adapter->pdev->dev;
struct be_queue_info *txq = &txo->q;
- struct be_eth_hdr_wrb *hdr;
bool map_single = false;
- struct be_eth_wrb *wrb;
- dma_addr_t busaddr;
u16 head = txq->head;
+ dma_addr_t busaddr;
+ int len;
- hdr = queue_head_node(txq);
- wrb_fill_hdr(adapter, hdr, skb, wrb_cnt, skb->len, skip_hw_vlan);
- be_dws_cpu_to_le(hdr, sizeof(*hdr));
-
- queue_head_inc(txq);
+ head = be_tx_get_wrb_hdr(txo);
if (skb->len > skb->data_len) {
- int len = skb_headlen(skb);
+ len = skb_headlen(skb);
busaddr = dma_map_single(dev, skb->data, len, DMA_TO_DEVICE);
if (dma_mapping_error(dev, busaddr))
goto dma_err;
map_single = true;
- wrb = queue_head_node(txq);
- wrb_fill(wrb, busaddr, len);
- queue_head_inc(txq);
+ be_tx_setup_wrb_frag(txo, busaddr, len);
copied += len;
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+ len = skb_frag_size(frag);
- busaddr = skb_frag_dma_map(dev, frag, 0,
- skb_frag_size(frag), DMA_TO_DEVICE);
+ busaddr = skb_frag_dma_map(dev, frag, 0, len, DMA_TO_DEVICE);
if (dma_mapping_error(dev, busaddr))
goto dma_err;
- wrb = queue_head_node(txq);
- wrb_fill(wrb, busaddr, skb_frag_size(frag));
- queue_head_inc(txq);
- copied += skb_frag_size(frag);
+ be_tx_setup_wrb_frag(txo, busaddr, len);
+ copied += len;
}
- BUG_ON(txo->sent_skb_list[head]);
- txo->sent_skb_list[head] = skb;
- txo->last_req_hdr = head;
- atomic_add(wrb_cnt, &txq->used);
- txo->last_req_wrb_cnt = wrb_cnt;
- txo->pend_wrb_cnt += wrb_cnt;
+ be_tx_setup_wrb_hdr(adapter, txo, wrb_params, skb, head);
be_tx_stats_update(txo, skb);
return wrb_cnt;
dma_err:
- /* Bring the queue back to the state it was in before this
- * routine was invoked.
- */
- txq->head = head;
- /* skip the first wrb (hdr); it's not mapped */
- queue_head_inc(txq);
- while (copied) {
- wrb = queue_head_node(txq);
- unmap_tx_frag(dev, wrb, map_single);
- map_single = false;
- copied -= le32_to_cpu(wrb->frag_len);
- adapter->drv_stats.dma_map_errors++;
- queue_head_inc(txq);
- }
- txq->head = head;
+ adapter->drv_stats.dma_map_errors++;
+ be_xmit_restore(adapter, txo, head, map_single, copied);
return 0;
}
@@ -869,7 +954,8 @@ static inline int qnq_async_evt_rcvd(struct be_adapter *adapter)
static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
struct sk_buff *skb,
- bool *skip_hw_vlan)
+ struct be_wrb_params
+ *wrb_params)
{
u16 vlan_tag = 0;
@@ -886,8 +972,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
/* f/w workaround to set skip_hw_vlan = 1, informs the F/W to
* skip VLAN insertion
*/
- if (skip_hw_vlan)
- *skip_hw_vlan = true;
+ BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1);
}
if (vlan_tag) {
@@ -905,8 +990,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
vlan_tag);
if (unlikely(!skb))
return skb;
- if (skip_hw_vlan)
- *skip_hw_vlan = true;
+ BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1);
}
return skb;
@@ -946,7 +1030,8 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *skb)
static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
struct sk_buff *skb,
- bool *skip_hw_vlan)
+ struct be_wrb_params
+ *wrb_params)
{
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
unsigned int eth_hdr_len;
@@ -970,7 +1055,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
*/
if (be_pvid_tagging_enabled(adapter) &&
veh->h_vlan_proto == htons(ETH_P_8021Q))
- *skip_hw_vlan = true;
+ BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1);
/* HW has a bug wherein it will calculate CSUM for VLAN
* pkts even though it is disabled.
@@ -978,7 +1063,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
*/
if (skb->ip_summed != CHECKSUM_PARTIAL &&
skb_vlan_tag_present(skb)) {
- skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
+ skb = be_insert_vlan_in_pkt(adapter, skb, wrb_params);
if (unlikely(!skb))
goto err;
}
@@ -1000,7 +1085,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
*/
if (be_ipv6_tx_stall_chk(adapter, skb) &&
be_vlan_tag_tx_chk(adapter, skb)) {
- skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
+ skb = be_insert_vlan_in_pkt(adapter, skb, wrb_params);
if (unlikely(!skb))
goto err;
}
@@ -1014,7 +1099,7 @@ err:
static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
struct sk_buff *skb,
- bool *skip_hw_vlan)
+ struct be_wrb_params *wrb_params)
{
/* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or
* less may cause a transmit stall on that port. So the work-around is
@@ -1026,7 +1111,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
}
if (BEx_chip(adapter) || lancer_chip(adapter)) {
- skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan);
+ skb = be_lancer_xmit_workarounds(adapter, skb, wrb_params);
if (!skb)
return NULL;
}
@@ -1060,24 +1145,26 @@ static void be_xmit_flush(struct be_adapter *adapter, struct be_tx_obj *txo)
static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
{
- bool skip_hw_vlan = false, flush = !skb->xmit_more;
struct be_adapter *adapter = netdev_priv(netdev);
u16 q_idx = skb_get_queue_mapping(skb);
struct be_tx_obj *txo = &adapter->tx_obj[q_idx];
- struct be_queue_info *txq = &txo->q;
+ struct be_wrb_params wrb_params = { 0 };
+ bool flush = !skb->xmit_more;
u16 wrb_cnt;
- skb = be_xmit_workarounds(adapter, skb, &skip_hw_vlan);
+ skb = be_xmit_workarounds(adapter, skb, &wrb_params);
if (unlikely(!skb))
goto drop;
- wrb_cnt = be_xmit_enqueue(adapter, txo, skb, skip_hw_vlan);
+ be_get_wrb_params_from_skb(adapter, skb, &wrb_params);
+
+ wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params);
if (unlikely(!wrb_cnt)) {
dev_kfree_skb_any(skb);
goto drop;
}
- if ((atomic_read(&txq->used) + BE_MAX_TX_FRAG_COUNT) >= txq->len) {
+ if (be_is_txq_full(txo)) {
netif_stop_subqueue(netdev, q_idx);
tx_stats(txo)->tx_stops++;
}
@@ -1991,18 +2078,23 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp, u32 frags_needed)
}
}
-static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
+static struct be_tx_compl_info *be_tx_compl_get(struct be_tx_obj *txo)
{
- struct be_eth_tx_compl *txcp = queue_tail_node(tx_cq);
+ struct be_queue_info *tx_cq = &txo->cq;
+ struct be_tx_compl_info *txcp = &txo->txcp;
+ struct be_eth_tx_compl *compl = queue_tail_node(tx_cq);
- if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0)
+ if (compl->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0)
return NULL;
+ /* Ensure load ordering of valid bit dword and other dwords below */
rmb();
- be_dws_le_to_cpu(txcp, sizeof(*txcp));
+ be_dws_le_to_cpu(compl, sizeof(*compl));
- txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0;
+ txcp->status = GET_TX_COMPL_BITS(status, compl);
+ txcp->end_index = GET_TX_COMPL_BITS(wrb_index, compl);
+ compl->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0;
queue_tail_inc(tx_cq);
return txcp;
}
@@ -2123,9 +2215,9 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
{
u16 end_idx, notified_idx, cmpl = 0, timeo = 0, num_wrbs = 0;
struct device *dev = &adapter->pdev->dev;
- struct be_tx_obj *txo;
+ struct be_tx_compl_info *txcp;
struct be_queue_info *txq;
- struct be_eth_tx_compl *txcp;
+ struct be_tx_obj *txo;
int i, pending_txqs;
/* Stop polling for compls when HW has been silent for 10ms */
@@ -2136,10 +2228,10 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
cmpl = 0;
num_wrbs = 0;
txq = &txo->q;
- while ((txcp = be_tx_compl_get(&txo->cq))) {
- end_idx = GET_TX_COMPL_BITS(wrb_index, txcp);
- num_wrbs += be_tx_compl_process(adapter, txo,
- end_idx);
+ while ((txcp = be_tx_compl_get(txo))) {
+ num_wrbs +=
+ be_tx_compl_process(adapter, txo,
+ txcp->end_index);
cmpl++;
}
if (cmpl) {
@@ -2147,7 +2239,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
atomic_sub(num_wrbs, &txq->used);
timeo = 0;
}
- if (atomic_read(&txq->used) == txo->pend_wrb_cnt)
+ if (!be_is_tx_compl_pending(txo))
pending_txqs--;
}
@@ -2498,7 +2590,7 @@ loop_continue:
return work_done;
}
-static inline void be_update_tx_err(struct be_tx_obj *txo, u32 status)
+static inline void be_update_tx_err(struct be_tx_obj *txo, u8 status)
{
switch (status) {
case BE_TX_COMP_HDR_PARSE_ERR:
@@ -2513,7 +2605,7 @@ static inline void be_update_tx_err(struct be_tx_obj *txo, u32 status)
}
}
-static inline void lancer_update_tx_err(struct be_tx_obj *txo, u32 status)
+static inline void lancer_update_tx_err(struct be_tx_obj *txo, u8 status)
{
switch (status) {
case LANCER_TX_COMP_LSO_ERR:
@@ -2538,22 +2630,18 @@ static inline void lancer_update_tx_err(struct be_tx_obj *txo, u32 status)
static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
int idx)
{
- struct be_eth_tx_compl *txcp;
int num_wrbs = 0, work_done = 0;
- u32 compl_status;
- u16 last_idx;
+ struct be_tx_compl_info *txcp;
- while ((txcp = be_tx_compl_get(&txo->cq))) {
- last_idx = GET_TX_COMPL_BITS(wrb_index, txcp);
- num_wrbs += be_tx_compl_process(adapter, txo, last_idx);
+ while ((txcp = be_tx_compl_get(txo))) {
+ num_wrbs += be_tx_compl_process(adapter, txo, txcp->end_index);
work_done++;
- compl_status = GET_TX_COMPL_BITS(status, txcp);
- if (compl_status) {
+ if (txcp->status) {
if (lancer_chip(adapter))
- lancer_update_tx_err(txo, compl_status);
+ lancer_update_tx_err(txo, txcp->status);
else
- be_update_tx_err(txo, compl_status);
+ be_update_tx_err(txo, txcp->status);
}
}
@@ -2564,7 +2652,7 @@ static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
/* As Tx wrbs have been freed up, wake up netdev queue
* if it was stopped due to lack of tx wrbs. */
if (__netif_subqueue_stopped(adapter->netdev, idx) &&
- atomic_read(&txo->q.used) < txo->q.len / 2) {
+ be_can_txq_wake(txo)) {
netif_wake_subqueue(adapter->netdev, idx);
}
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index 22e0cad1b4b5..401abf7254d3 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -1411,6 +1411,8 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(err < 0)) {
netdev_info(dev, "TX trigger error %d\n", err);
d->hdr.state = VIO_DESC_FREE;
+ skb = port->tx_bufs[txi].skb;
+ port->tx_bufs[txi].skb = NULL;
dev->stats.tx_carrier_errors++;
goto out_dropped;
}
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 9cdfb3fe9c15..3c8dfe5e46ed 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -1477,6 +1477,7 @@ static void tiocmget_intr_callback(struct urb *urb)
struct uart_icount *icount;
struct hso_serial_state_notification *serial_state_notification;
struct usb_device *usb;
+ struct usb_interface *interface;
int if_num;
/* Sanity checks */
@@ -1494,7 +1495,9 @@ static void tiocmget_intr_callback(struct urb *urb)
BUG_ON((serial->parent->port_spec & HSO_PORT_MASK) != HSO_PORT_MODEM);
usb = serial->parent->usb;
- if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber;
+ interface = serial->parent->interface;
+
+ if_num = interface->cur_altsetting->desc.bInterfaceNumber;
/* wIndex should be the USB interface number of the port to which the
* notification applies, which should always be the Modem port.
@@ -1675,6 +1678,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
unsigned long flags;
int if_num;
struct hso_serial *serial = tty->driver_data;
+ struct usb_interface *interface;
/* sanity check */
if (!serial) {
@@ -1685,7 +1689,8 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
if ((serial->parent->port_spec & HSO_PORT_MASK) != HSO_PORT_MODEM)
return -EINVAL;
- if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber;
+ interface = serial->parent->interface;
+ if_num = interface->cur_altsetting->desc.bInterfaceNumber;
spin_lock_irqsave(&serial->serial_lock, flags);
if (set & TIOCM_RTS)
@@ -2808,7 +2813,7 @@ static int hso_get_config_data(struct usb_interface *interface)
{
struct usb_device *usbdev = interface_to_usbdev(interface);
u8 *config_data = kmalloc(17, GFP_KERNEL);
- u32 if_num = interface->altsetting->desc.bInterfaceNumber;
+ u32 if_num = interface->cur_altsetting->desc.bInterfaceNumber;
s32 result;
if (!config_data)
@@ -2886,7 +2891,7 @@ static int hso_probe(struct usb_interface *interface,
return -ENODEV;
}
- if_num = interface->altsetting->desc.bInterfaceNumber;
+ if_num = interface->cur_altsetting->desc.bInterfaceNumber;
/* Get the interface/port specification from either driver_info or from
* the device itself */
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 438fc6bcaef1..5065538dd03b 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -104,7 +104,8 @@
#define USB_TX_AGG 0xd40a
#define USB_RX_BUF_TH 0xd40c
#define USB_USB_TIMER 0xd428
-#define USB_RX_EARLY_AGG 0xd42c
+#define USB_RX_EARLY_TIMEOUT 0xd42c
+#define USB_RX_EARLY_SIZE 0xd42e
#define USB_PM_CTRL_STATUS 0xd432
#define USB_TX_DMA 0xd434
#define USB_TOLERANCE 0xd490
@@ -349,10 +350,10 @@
/* USB_MISC_0 */
#define PCUT_STATUS 0x0001
-/* USB_RX_EARLY_AGG */
-#define EARLY_AGG_SUPPER 0x0e832981
-#define EARLY_AGG_HIGH 0x0e837a12
-#define EARLY_AGG_SLOW 0x0e83ffff
+/* USB_RX_EARLY_TIMEOUT */
+#define COALESCE_SUPER 85000U
+#define COALESCE_HIGH 250000U
+#define COALESCE_SLOW 524280U
/* USB_WDT11_CTRL */
#define TIMER11_EN 0x0001
@@ -606,6 +607,7 @@ struct r8152 {
u32 saved_wolopts;
u32 msg_enable;
u32 tx_qlen;
+ u32 coalesce;
u16 ocp_base;
u8 *intr_buff;
u8 version;
@@ -2142,28 +2144,19 @@ static int rtl8152_enable(struct r8152 *tp)
return rtl_enable(tp);
}
-static void r8153_set_rx_agg(struct r8152 *tp)
+static void r8153_set_rx_early_timeout(struct r8152 *tp)
{
- u8 speed;
+ u32 ocp_data = tp->coalesce / 8;
- speed = rtl8152_get_speed(tp);
- if (speed & _1000bps) {
- if (tp->udev->speed == USB_SPEED_SUPER) {
- ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH,
- RX_THR_SUPPER);
- ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG,
- EARLY_AGG_SUPPER);
- } else {
- ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH,
- RX_THR_HIGH);
- ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG,
- EARLY_AGG_HIGH);
- }
- } else {
- ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_SLOW);
- ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG,
- EARLY_AGG_SLOW);
- }
+ ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT, ocp_data);
+}
+
+static void r8153_set_rx_early_size(struct r8152 *tp)
+{
+ u32 mtu = tp->netdev->mtu;
+ u32 ocp_data = (agg_buf_sz - mtu - VLAN_ETH_HLEN - VLAN_HLEN) / 4;
+
+ ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, ocp_data);
}
static int rtl8153_enable(struct r8152 *tp)
@@ -2173,7 +2166,8 @@ static int rtl8153_enable(struct r8152 *tp)
set_tx_qlen(tp);
rtl_set_eee_plus(tp);
- r8153_set_rx_agg(tp);
+ r8153_set_rx_early_timeout(tp);
+ r8153_set_rx_early_size(tp);
return rtl_enable(tp);
}
@@ -3719,6 +3713,61 @@ out:
return ret;
}
+static int rtl8152_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *coalesce)
+{
+ struct r8152 *tp = netdev_priv(netdev);
+
+ switch (tp->version) {
+ case RTL_VER_01:
+ case RTL_VER_02:
+ return -EOPNOTSUPP;
+ default:
+ break;
+ }
+
+ coalesce->rx_coalesce_usecs = tp->coalesce;
+
+ return 0;
+}
+
+static int rtl8152_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *coalesce)
+{
+ struct r8152 *tp = netdev_priv(netdev);
+ int ret;
+
+ switch (tp->version) {
+ case RTL_VER_01:
+ case RTL_VER_02:
+ return -EOPNOTSUPP;
+ default:
+ break;
+ }
+
+ if (coalesce->rx_coalesce_usecs > COALESCE_SLOW)
+ return -EINVAL;
+
+ ret = usb_autopm_get_interface(tp->intf);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&tp->control);
+
+ if (tp->coalesce != coalesce->rx_coalesce_usecs) {
+ tp->coalesce = coalesce->rx_coalesce_usecs;
+
+ if (netif_running(tp->netdev) && netif_carrier_ok(netdev))
+ r8153_set_rx_early_timeout(tp);
+ }
+
+ mutex_unlock(&tp->control);
+
+ usb_autopm_put_interface(tp->intf);
+
+ return ret;
+}
+
static struct ethtool_ops ops = {
.get_drvinfo = rtl8152_get_drvinfo,
.get_settings = rtl8152_get_settings,
@@ -3732,6 +3781,8 @@ static struct ethtool_ops ops = {
.get_strings = rtl8152_get_strings,
.get_sset_count = rtl8152_get_sset_count,
.get_ethtool_stats = rtl8152_get_ethtool_stats,
+ .get_coalesce = rtl8152_get_coalesce,
+ .set_coalesce = rtl8152_set_coalesce,
.get_eee = rtl_ethtool_get_eee,
.set_eee = rtl_ethtool_set_eee,
};
@@ -3783,6 +3834,7 @@ out:
static int rtl8152_change_mtu(struct net_device *dev, int new_mtu)
{
struct r8152 *tp = netdev_priv(dev);
+ int ret;
switch (tp->version) {
case RTL_VER_01:
@@ -3795,9 +3847,22 @@ static int rtl8152_change_mtu(struct net_device *dev, int new_mtu)
if (new_mtu < 68 || new_mtu > RTL8153_MAX_MTU)
return -EINVAL;
+ ret = usb_autopm_get_interface(tp->intf);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&tp->control);
+
dev->mtu = new_mtu;
- return 0;
+ if (netif_running(dev) && netif_carrier_ok(dev))
+ r8153_set_rx_early_size(tp);
+
+ mutex_unlock(&tp->control);
+
+ usb_autopm_put_interface(tp->intf);
+
+ return ret;
}
static const struct net_device_ops rtl8152_netdev_ops = {
@@ -3966,6 +4031,18 @@ static int rtl8152_probe(struct usb_interface *intf,
tp->mii.reg_num_mask = 0x1f;
tp->mii.phy_id = R8152_PHY_ID;
+ switch (udev->speed) {
+ case USB_SPEED_SUPER:
+ tp->coalesce = COALESCE_SUPER;
+ break;
+ case USB_SPEED_HIGH:
+ tp->coalesce = COALESCE_HIGH;
+ break;
+ default:
+ tp->coalesce = COALESCE_SLOW;
+ break;
+ }
+
intf->needs_remote_wakeup = 1;
tp->rtl_ops.init(tp);
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index d6d2f0f00caa..d372ebfd933d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1386,7 +1386,8 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
lockdep_assert_held(&ar->conf_mutex);
bss = cfg80211_get_bss(ar->hw->wiphy, ar->hw->conf.chandef.chan,
- info->bssid, NULL, 0, 0, 0);
+ info->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY,
+ IEEE80211_PRIVACY_ANY);
if (bss) {
const struct cfg80211_bss_ies *ies;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 85da63a67faf..d740f14f3539 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -686,20 +686,21 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
{
struct ath6kl *ar = vif->ar;
struct cfg80211_bss *bss;
- u16 cap_mask, cap_val;
+ u16 cap_val;
+ enum ieee80211_bss_type bss_type;
u8 *ie;
if (nw_type & ADHOC_NETWORK) {
- cap_mask = WLAN_CAPABILITY_IBSS;
cap_val = WLAN_CAPABILITY_IBSS;
+ bss_type = IEEE80211_BSS_TYPE_IBSS;
} else {
- cap_mask = WLAN_CAPABILITY_ESS;
cap_val = WLAN_CAPABILITY_ESS;
+ bss_type = IEEE80211_BSS_TYPE_ESS;
}
bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
vif->ssid, vif->ssid_len,
- cap_mask, cap_val);
+ bss_type, IEEE80211_PRIVACY_ANY);
if (bss == NULL) {
/*
* Since cfg80211 may not yet know about the BSS,
@@ -1495,6 +1496,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
const char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type,
u32 *flags,
struct vif_params *params)
@@ -1513,7 +1515,7 @@ static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
return ERR_PTR(-EINVAL);
}
- wdev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
+ wdev = ath6kl_interface_add(ar, name, name_assign_type, type, if_idx, nw_type);
if (!wdev)
return ERR_PTR(-ENOMEM);
@@ -3633,13 +3635,14 @@ void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
}
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type,
u8 fw_vif_idx, u8 nw_type)
{
struct net_device *ndev;
struct ath6kl_vif *vif;
- ndev = alloc_netdev(sizeof(*vif), name, NET_NAME_UNKNOWN, ether_setup);
+ ndev = alloc_netdev(sizeof(*vif), name, name_assign_type, ether_setup);
if (!ndev)
return NULL;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
index b59becd91aea..5aa57a7639bf 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.h
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -25,6 +25,7 @@ enum ath6kl_cfg_suspend_mode {
};
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type,
u8 fw_vif_idx, u8 nw_type);
void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c
index 0df74b245af4..4ec02cea0f43 100644
--- a/drivers/net/wireless/ath/ath6kl/core.c
+++ b/drivers/net/wireless/ath/ath6kl/core.c
@@ -211,8 +211,8 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
rtnl_lock();
/* Add an initial station interface */
- wdev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0,
- INFRA_NETWORK);
+ wdev = ath6kl_interface_add(ar, "wlan%d", NET_NAME_ENUM,
+ NL80211_IFTYPE_STATION, 0, INFRA_NETWORK);
rtnl_unlock();
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 2d5ea21be47e..adfd815e3f7d 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -395,7 +395,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
sme->ssid, sme->ssid_len,
- WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+ IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
if (!bss) {
wil_err(wil, "Unable to find BSS\n");
return -ENOENT;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
index b59b8c6c42ab..bcbccba4cdbf 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
@@ -625,6 +625,7 @@ static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
const char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type,
u32 *flags,
struct vif_params *params)
@@ -648,7 +649,7 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_P2P_DEVICE:
- wdev = brcmf_p2p_add_vif(wiphy, name, type, flags, params);
+ wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
if (!IS_ERR(wdev))
brcmf_cfg80211_update_proto_addr_mode(wdev);
return wdev;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index effb48ebd864..b44ea85dd9db 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -2246,11 +2246,13 @@ static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p,
*
* @wiphy: wiphy device of new interface.
* @name: name of the new interface.
+ * @name_assign_type: origin of the interface name
* @type: nl80211 interface type.
* @flags: not used.
* @params: contains mac address for P2P device.
*/
struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
@@ -2310,6 +2312,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
}
strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
+ ifp->ndev->name_assign_type = name_assign_type;
err = brcmf_net_attach(ifp, true);
if (err) {
brcmf_err("Registering netdevice failed\n");
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
index 6821b26224be..872f382d9e49 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h
@@ -149,6 +149,7 @@ struct brcmf_p2p_info {
s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg);
void brcmf_p2p_detach(struct brcmf_p2p_info *p2p);
struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params);
int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev);
diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c
index 4a47c7f8a246..1b58b2e2a538 100644
--- a/drivers/net/wireless/cw1200/sta.c
+++ b/drivers/net/wireless/cw1200/sta.c
@@ -1240,8 +1240,8 @@ static void cw1200_do_join(struct cw1200_common *priv)
bssid = priv->vif->bss_conf.bssid;
- bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel,
- bssid, NULL, 0, 0, 0);
+ bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel, bssid, NULL, 0,
+ IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
if (!bss && !conf->ibss_joined) {
wsm_unlock_tx(priv);
diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig
index 21de4fe6cf2d..d6ec44d7a391 100644
--- a/drivers/net/wireless/ipw2x00/Kconfig
+++ b/drivers/net/wireless/ipw2x00/Kconfig
@@ -66,7 +66,7 @@ config IPW2100_DEBUG
config IPW2200
tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
depends on PCI && CFG80211
- select CFG80211_WEXT
+ select CFG80211_WEXT_EXPORT
select WIRELESS_EXT
select WEXT_SPY
select WEXT_PRIV
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index cceb026e0793..5abd62ed8cb4 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -1130,20 +1130,23 @@ done:
IWL_DEBUG_MAC80211(priv, "leave\n");
}
-static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum ieee80211_rssi_event rssi_event)
+static void iwlagn_mac_event_callback(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const struct ieee80211_event *event)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+ if (event->type != RSSI_EVENT)
+ return;
+
IWL_DEBUG_MAC80211(priv, "enter\n");
mutex_lock(&priv->mutex);
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist) {
- if (rssi_event == RSSI_EVENT_LOW)
+ if (event->u.rssi.data == RSSI_EVENT_LOW)
priv->bt_enable_pspoll = true;
- else if (rssi_event == RSSI_EVENT_HIGH)
+ else if (event->u.rssi.data == RSSI_EVENT_HIGH)
priv->bt_enable_pspoll = false;
iwlagn_send_advance_bt_config(priv);
@@ -1614,7 +1617,7 @@ const struct ieee80211_ops iwlagn_hw_ops = {
.channel_switch = iwlagn_mac_channel_switch,
.flush = iwlagn_mac_flush,
.tx_last_beacon = iwlagn_mac_tx_last_beacon,
- .rssi_callback = iwlagn_mac_rssi_callback,
+ .event_callback = iwlagn_mac_event_callback,
.set_tim = iwlagn_mac_set_tim,
};
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c
index 770b0e2a9b46..13a0a03158de 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex.c
@@ -807,7 +807,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
}
void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- enum ieee80211_rssi_event rssi_event)
+ enum ieee80211_rssi_event_data rssi_event)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_bt_iterator_data data = {
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
index 4f303639147b..d954591e0be5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
@@ -1128,7 +1128,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
}
void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- enum ieee80211_rssi_event rssi_event)
+ enum ieee80211_rssi_event_data rssi_event)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_bt_iterator_data data = {
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 500064f5d8f1..2b7e6cb1dbd9 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -1289,7 +1289,7 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- enum ieee80211_rssi_event rssi_event);
+ enum ieee80211_rssi_event_data);
void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm);
u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
struct ieee80211_sta *sta);
@@ -1309,7 +1309,7 @@ int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- enum ieee80211_rssi_event rssi_event);
+ enum ieee80211_rssi_event_data);
u16 iwl_mvm_coex_agg_time_limit_old(struct iwl_mvm *mvm,
struct ieee80211_sta *sta);
bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index a92985a6ea21..1a4d558022d8 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -1356,8 +1356,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
/* Find the BSS we want using available scan results */
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
- sme->ssid, sme->ssid_len,
- WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+ sme->ssid, sme->ssid_len, IEEE80211_BSS_TYPE_ESS,
+ IEEE80211_PRIVACY_ANY);
if (!bss) {
wiphy_err(wiphy, "assoc: bss %pM not in scan results\n",
sme->bssid);
@@ -2000,7 +2000,7 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
* bss list is populated already */
bss = cfg80211_get_bss(wiphy, params->chandef.chan, params->bssid,
params->ssid, params->ssid_len,
- WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+ IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY);
if (bss) {
ret = lbs_ibss_join_existing(priv, params, bss);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 4a4c6586a8d2..941925991476 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -330,6 +330,83 @@ static const struct ieee80211_rate hwsim_rates[] = {
{ .bitrate = 540 }
};
+#define OUI_QCA 0x001374
+#define QCA_NL80211_SUBCMD_TEST 1
+enum qca_nl80211_vendor_subcmds {
+ QCA_WLAN_VENDOR_ATTR_TEST = 8,
+ QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_TEST
+};
+
+static const struct nla_policy
+hwsim_vendor_test_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = {
+ [QCA_WLAN_VENDOR_ATTR_MAX] = { .type = NLA_U32 },
+};
+
+static int mac80211_hwsim_vendor_cmd_test(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct sk_buff *skb;
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+ int err;
+ u32 val;
+
+ err = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len,
+ hwsim_vendor_test_policy);
+ if (err)
+ return err;
+ if (!tb[QCA_WLAN_VENDOR_ATTR_TEST])
+ return -EINVAL;
+ val = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TEST]);
+ wiphy_debug(wiphy, "%s: test=%u\n", __func__, val);
+
+ /* Send a vendor event as a test. Note that this would not normally be
+ * done within a command handler, but rather, based on some other
+ * trigger. For simplicity, this command is used to trigger the event
+ * here.
+ *
+ * event_idx = 0 (index in mac80211_hwsim_vendor_commands)
+ */
+ skb = cfg80211_vendor_event_alloc(wiphy, wdev, 100, 0, GFP_KERNEL);
+ if (skb) {
+ /* skb_put() or nla_put() will fill up data within
+ * NL80211_ATTR_VENDOR_DATA.
+ */
+
+ /* Add vendor data */
+ nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1);
+
+ /* Send the event - this will call nla_nest_end() */
+ cfg80211_vendor_event(skb, GFP_KERNEL);
+ }
+
+ /* Send a response to the command */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 10);
+ if (!skb)
+ return -ENOMEM;
+
+ /* skb_put() or nla_put() will fill up data within
+ * NL80211_ATTR_VENDOR_DATA
+ */
+ nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 2);
+
+ return cfg80211_vendor_cmd_reply(skb);
+}
+
+static struct wiphy_vendor_command mac80211_hwsim_vendor_commands[] = {
+ {
+ .info = { .vendor_id = OUI_QCA,
+ .subcmd = QCA_NL80211_SUBCMD_TEST },
+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = mac80211_hwsim_vendor_cmd_test,
+ }
+};
+
+/* Advertise support vendor specific events */
+static const struct nl80211_vendor_cmd_info mac80211_hwsim_vendor_events[] = {
+ { .vendor_id = OUI_QCA, .subcmd = 1 },
+};
+
static const struct ieee80211_iface_limit hwsim_if_limits[] = {
{ .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
{ .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
@@ -906,8 +983,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
goto nla_put_failure;
}
- if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
- ETH_ALEN, data->addresses[1].addr))
+ if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, hdr->addr2))
goto nla_put_failure;
/* We get the skb->data */
@@ -1519,21 +1595,16 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
vp->aid = info->aid;
}
- if (changed & BSS_CHANGED_BEACON_INT) {
- wiphy_debug(hw->wiphy, " BCNINT: %d\n", info->beacon_int);
- data->beacon_int = info->beacon_int * 1024;
- }
-
if (changed & BSS_CHANGED_BEACON_ENABLED) {
- wiphy_debug(hw->wiphy, " BCN EN: %d\n", info->enable_beacon);
+ wiphy_debug(hw->wiphy, " BCN EN: %d (BI=%u)\n",
+ info->enable_beacon, info->beacon_int);
vp->bcn_en = info->enable_beacon;
if (data->started &&
!hrtimer_is_queued(&data->beacon_timer.timer) &&
info->enable_beacon) {
u64 tsf, until_tbtt;
u32 bcn_int;
- if (WARN_ON(!data->beacon_int))
- data->beacon_int = 1000 * 1024;
+ data->beacon_int = info->beacon_int * 1024;
tsf = mac80211_hwsim_get_tsf(hw, vif);
bcn_int = data->beacon_int;
until_tbtt = bcn_int - do_div(tsf, bcn_int);
@@ -1547,8 +1618,10 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
mac80211_hwsim_bcn_en_iter, &count);
wiphy_debug(hw->wiphy, " beaconing vifs remaining: %u",
count);
- if (count == 0)
+ if (count == 0) {
tasklet_hrtimer_cancel(&data->beacon_timer);
+ data->beacon_int = 0;
+ }
}
}
@@ -2417,6 +2490,12 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
hw->max_rates = 4;
hw->max_rate_tries = 11;
+ hw->wiphy->vendor_commands = mac80211_hwsim_vendor_commands;
+ hw->wiphy->n_vendor_commands =
+ ARRAY_SIZE(mac80211_hwsim_vendor_commands);
+ hw->wiphy->vendor_events = mac80211_hwsim_vendor_events;
+ hw->wiphy->n_vendor_events = ARRAY_SIZE(mac80211_hwsim_vendor_events);
+
if (param->reg_strict)
hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
if (param->regd) {
@@ -2608,7 +2687,7 @@ static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr)
spin_lock_bh(&hwsim_radio_lock);
list_for_each_entry(data, &hwsim_radios, list) {
- if (memcmp(data->addresses[1].addr, addr, ETH_ALEN) == 0) {
+ if (mac80211_hwsim_addr_match(data, addr)) {
_found = true;
break;
}
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 41c8e25df954..2d489bfaea08 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1954,13 +1954,13 @@ done:
if (mode == NL80211_IFTYPE_ADHOC)
bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
bssid, ssid, ssid_len,
- WLAN_CAPABILITY_IBSS,
- WLAN_CAPABILITY_IBSS);
+ IEEE80211_BSS_TYPE_IBSS,
+ IEEE80211_PRIVACY_ANY);
else
bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
bssid, ssid, ssid_len,
- WLAN_CAPABILITY_ESS,
- WLAN_CAPABILITY_ESS);
+ IEEE80211_BSS_TYPE_ESS,
+ IEEE80211_PRIVACY_ANY);
if (!bss) {
if (is_scanning_required) {
@@ -2399,10 +2399,11 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
#define MWIFIEX_MAX_WQ_LEN 30
/*
- * create a new virtual interface with the given name
+ * create a new virtual interface with the given name and name assign type
*/
struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
const char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type,
u32 *flags,
struct vif_params *params)
@@ -2523,7 +2524,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
}
dev = alloc_netdev_mqs(sizeof(struct mwifiex_private *), name,
- NET_NAME_UNKNOWN, ether_setup,
+ name_assign_type, ether_setup,
IEEE80211_NUM_ACS, 1);
if (!dev) {
wiphy_err(wiphy, "no memory available for netdevice\n");
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 7e74b4fccddd..6f55e84fcab1 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -466,7 +466,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
rtnl_lock();
/* Create station interface by default */
- wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d",
+ wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM,
NL80211_IFTYPE_STATION, NULL, NULL);
if (IS_ERR(wdev)) {
dev_err(adapter->dev, "cannot create default STA interface\n");
@@ -475,7 +475,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
}
if (driver_mode & MWIFIEX_DRIVER_MODE_UAP) {
- wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d",
+ wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM,
NL80211_IFTYPE_AP, NULL, NULL);
if (IS_ERR(wdev)) {
dev_err(adapter->dev, "cannot create AP interface\n");
@@ -485,7 +485,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
}
if (driver_mode & MWIFIEX_DRIVER_MODE_P2P) {
- wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d",
+ wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", NET_NAME_ENUM,
NL80211_IFTYPE_P2P_CLIENT, NULL,
NULL);
if (IS_ERR(wdev)) {
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index f0a6af179af0..3f0625f22265 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -1318,6 +1318,7 @@ u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type);
struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
const char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type,
u32 *flags,
struct vif_params *params);
diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig
index 6d831d4d1b5f..f6fa3f4e294f 100644
--- a/drivers/net/wireless/orinoco/Kconfig
+++ b/drivers/net/wireless/orinoco/Kconfig
@@ -2,7 +2,7 @@ config HERMES
tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
depends on (PPC_PMAC || PCI || PCMCIA)
depends on CFG80211
- select CFG80211_WEXT
+ select CFG80211_WEXT_EXPORT
select WIRELESS_EXT
select WEXT_SPY
select WEXT_PRIV
diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c
index c28f06854195..548bb9e7e91e 100644
--- a/drivers/net/wireless/ti/wl18xx/event.c
+++ b/drivers/net/wireless/ti/wl18xx/event.c
@@ -77,7 +77,7 @@ static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel,
wl1271_debug(DEBUG_EVENT,
"SMART_CONFIG_SYNC_EVENT_ID, freq: %d (chan: %d band %d)",
freq, sync_channel, sync_band);
- skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, 20,
+ skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, NULL, 20,
WLCORE_VENDOR_EVENT_SC_SYNC,
GFP_KERNEL);
@@ -98,7 +98,7 @@ static int wlcore_smart_config_decode_event(struct wl1271 *wl,
wl1271_debug(DEBUG_EVENT, "SMART_CONFIG_DECODE_EVENT_ID");
wl1271_dump_ascii(DEBUG_EVENT, "SSID:", ssid, ssid_len);
- skb = cfg80211_vendor_event_alloc(wl->hw->wiphy,
+ skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, NULL,
ssid_len + pwd_len + 20,
WLCORE_VENDOR_EVENT_SC_DECODE,
GFP_KERNEL);
diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
index 537bd8214efe..a6116fdc8678 100644
--- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
@@ -2580,6 +2580,7 @@ static const struct net_device_ops rtw_cfg80211_monitor_if_ops = {
};
static int rtw_cfg80211_add_monitor_if(struct rtw_adapter *padapter, char *name,
+ unsigned char name_assign_type,
struct net_device **ndev)
{
int ret = 0;
@@ -2612,6 +2613,7 @@ static int rtw_cfg80211_add_monitor_if(struct rtw_adapter *padapter, char *name,
mon_ndev->type = ARPHRD_IEEE80211_RADIOTAP;
strncpy(mon_ndev->name, name, IFNAMSIZ);
mon_ndev->name[IFNAMSIZ - 1] = 0;
+ mon_ndev->name_assign_type = name_assign_type;
mon_ndev->destructor = rtw_ndev_destructor;
mon_ndev->netdev_ops = &rtw_cfg80211_monitor_if_ops;
@@ -2654,6 +2656,7 @@ out:
static struct wireless_dev *
cfg80211_rtw_add_virtual_intf(struct wiphy *wiphy, const char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
@@ -2673,7 +2676,8 @@ cfg80211_rtw_add_virtual_intf(struct wiphy *wiphy, const char *name,
break;
case NL80211_IFTYPE_MONITOR:
ret =
- rtw_cfg80211_add_monitor_if(padapter, (char *)name, &ndev);
+ rtw_cfg80211_add_monitor_if(padapter, (char *)name,
+ name_assign_type, &ndev);
break;
case NL80211_IFTYPE_P2P_CLIENT:
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 2c677afeea47..b5a6470e686c 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -111,7 +111,9 @@ struct ip_mc_list {
extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u16 proto);
extern int igmp_rcv(struct sk_buff *);
+extern int __ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
+extern int __ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr);
extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr);
extern void ip_mc_drop_socket(struct sock *sk);
extern int ip_mc_source(int add, int omode, struct sock *sk,
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 30007afe70b3..d898b32dedcc 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -870,8 +870,7 @@ unsigned int skb_seq_read(unsigned int consumed, const u8 **data,
void skb_abort_seq_read(struct skb_seq_state *st);
unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
- unsigned int to, struct ts_config *config,
- struct ts_state *state);
+ unsigned int to, struct ts_config *config);
/*
* Packet hash types specify the type of hash in skb_set_hash.
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 64e09e1e8099..ab667fbc743d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -215,6 +215,39 @@ enum ieee80211_rate_flags {
};
/**
+ * enum ieee80211_bss_type - BSS type filter
+ *
+ * @IEEE80211_BSS_TYPE_ESS: Infrastructure BSS
+ * @IEEE80211_BSS_TYPE_PBSS: Personal BSS
+ * @IEEE80211_BSS_TYPE_IBSS: Independent BSS
+ * @IEEE80211_BSS_TYPE_MBSS: Mesh BSS
+ * @IEEE80211_BSS_TYPE_ANY: Wildcard value for matching any BSS type
+ */
+enum ieee80211_bss_type {
+ IEEE80211_BSS_TYPE_ESS,
+ IEEE80211_BSS_TYPE_PBSS,
+ IEEE80211_BSS_TYPE_IBSS,
+ IEEE80211_BSS_TYPE_MBSS,
+ IEEE80211_BSS_TYPE_ANY
+};
+
+/**
+ * enum ieee80211_privacy - BSS privacy filter
+ *
+ * @IEEE80211_PRIVACY_ON: privacy bit set
+ * @IEEE80211_PRIVACY_OFF: privacy bit clear
+ * @IEEE80211_PRIVACY_ANY: Wildcard value for matching any privacy setting
+ */
+enum ieee80211_privacy {
+ IEEE80211_PRIVACY_ON,
+ IEEE80211_PRIVACY_OFF,
+ IEEE80211_PRIVACY_ANY
+};
+
+#define IEEE80211_PRIVACY(x) \
+ ((x) ? IEEE80211_PRIVACY_ON : IEEE80211_PRIVACY_OFF)
+
+/**
* struct ieee80211_rate - bitrate definition
*
* This structure describes a bitrate that an 802.11 PHY can
@@ -2423,6 +2456,7 @@ struct cfg80211_ops {
struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy,
const char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type,
u32 *flags,
struct vif_params *params);
@@ -4012,14 +4046,16 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
struct ieee80211_channel *channel,
const u8 *bssid,
const u8 *ssid, size_t ssid_len,
- u16 capa_mask, u16 capa_val);
+ enum ieee80211_bss_type bss_type,
+ enum ieee80211_privacy);
static inline struct cfg80211_bss *
cfg80211_get_ibss(struct wiphy *wiphy,
struct ieee80211_channel *channel,
const u8 *ssid, size_t ssid_len)
{
return cfg80211_get_bss(wiphy, channel, NULL, ssid, ssid_len,
- WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+ IEEE80211_BSS_TYPE_IBSS,
+ IEEE80211_PRIVACY_ANY);
}
/**
@@ -4260,6 +4296,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
int approxlen);
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
enum nl80211_commands cmd,
enum nl80211_attrs attr,
int vendor_event_idx,
@@ -4314,6 +4351,7 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb);
/**
* cfg80211_vendor_event_alloc - allocate vendor-specific event skb
* @wiphy: the wiphy
+ * @wdev: the wireless device
* @event_idx: index of the vendor event in the wiphy's vendor_events
* @approxlen: an upper bound of the length of the data that will
* be put into the skb
@@ -4322,16 +4360,20 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb);
* This function allocates and pre-fills an skb for an event on the
* vendor-specific multicast group.
*
+ * If wdev != NULL, both the ifindex and identifier of the specified
+ * wireless device are added to the event message before the vendor data
+ * attribute.
+ *
* When done filling the skb, call cfg80211_vendor_event() with the
* skb to send the event.
*
* Return: An allocated and pre-filled skb. %NULL if any errors happen.
*/
static inline struct sk_buff *
-cfg80211_vendor_event_alloc(struct wiphy *wiphy, int approxlen,
- int event_idx, gfp_t gfp)
+cfg80211_vendor_event_alloc(struct wiphy *wiphy, struct wireless_dev *wdev,
+ int approxlen, int event_idx, gfp_t gfp)
{
- return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_VENDOR,
+ return __cfg80211_alloc_event_skb(wiphy, wdev, NL80211_CMD_VENDOR,
NL80211_ATTR_VENDOR_DATA,
event_idx, approxlen, gfp);
}
@@ -4432,7 +4474,7 @@ static inline int cfg80211_testmode_reply(struct sk_buff *skb)
static inline struct sk_buff *
cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp)
{
- return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_TESTMODE,
+ return __cfg80211_alloc_event_skb(wiphy, NULL, NL80211_CMD_TESTMODE,
NL80211_ATTR_TESTDATA, -1,
approxlen, gfp);
}
@@ -4862,6 +4904,17 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev,
bool ieee80211_operating_class_to_band(u8 operating_class,
enum ieee80211_band *band);
+/**
+ * ieee80211_chandef_to_operating_class - convert chandef to operation class
+ *
+ * @chandef: the chandef to convert
+ * @op_class: a pointer to the resulting operating class
+ *
+ * Returns %true if the conversion was successful, %false otherwise.
+ */
+bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
+ u8 *op_class);
+
/*
* cfg80211_tdls_oper_request - request userspace to perform TDLS operation
* @dev: the device on which the operation is requested
diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h
index a830b01baba4..8f81bbbc38fc 100644
--- a/include/net/iw_handler.h
+++ b/include/net/iw_handler.h
@@ -519,6 +519,17 @@ iwe_stream_add_event(struct iw_request_info *info, char *stream, char *ends,
return stream;
}
+static inline char *
+iwe_stream_add_event_check(struct iw_request_info *info, char *stream,
+ char *ends, struct iw_event *iwe, int event_len)
+{
+ char *res = iwe_stream_add_event(info, stream, ends, iwe, event_len);
+
+ if (res == stream)
+ return ERR_PTR(-E2BIG);
+ return res;
+}
+
/*------------------------------------------------------------------*/
/*
* Wrapper to add an short Wireless Event containing a pointer to a
@@ -545,6 +556,17 @@ iwe_stream_add_point(struct iw_request_info *info, char *stream, char *ends,
return stream;
}
+static inline char *
+iwe_stream_add_point_check(struct iw_request_info *info, char *stream,
+ char *ends, struct iw_event *iwe, char *extra)
+{
+ char *res = iwe_stream_add_point(info, stream, ends, iwe, extra);
+
+ if (res == stream)
+ return ERR_PTR(-E2BIG);
+ return res;
+}
+
/*------------------------------------------------------------------*/
/*
* Wrapper to add a value to a Wireless Event in a stream of events.
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d52914b75331..201bc68e0cff 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -301,17 +301,86 @@ enum ieee80211_bss_change {
#define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4
/**
- * enum ieee80211_rssi_event - RSSI threshold event
- * An indicator for when RSSI goes below/above a certain threshold.
- * @RSSI_EVENT_HIGH: AP's rssi crossed the high threshold set by the driver.
- * @RSSI_EVENT_LOW: AP's rssi crossed the low threshold set by the driver.
+ * 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
*/
-enum ieee80211_rssi_event {
+enum ieee80211_event_type {
+ RSSI_EVENT,
+ MLME_EVENT,
+};
+
+/**
+ * enum ieee80211_rssi_event_data - relevant when event type is %RSSI_EVENT
+ * @RSSI_EVENT_HIGH: AP's rssi went below the threshold set by the driver.
+ * @RSSI_EVENT_LOW: AP's rssi went above the threshold set by the driver.
+ */
+enum ieee80211_rssi_event_data {
RSSI_EVENT_HIGH,
RSSI_EVENT_LOW,
};
/**
+ * enum ieee80211_rssi_event - data attached to an %RSSI_EVENT
+ * @data: See &enum ieee80211_rssi_event_data
+ */
+struct ieee80211_rssi_event {
+ enum ieee80211_rssi_event_data data;
+};
+
+/**
+ * enum ieee80211_mlme_event_data - relevant when event type is %MLME_EVENT
+ * @AUTH_EVENT: the MLME operation is authentication
+ * @ASSOC_EVENT: the MLME operation is association
+ * @DEAUTH_RX_EVENT: deauth received..
+ * @DEAUTH_TX_EVENT: deauth sent.
+ */
+enum ieee80211_mlme_event_data {
+ AUTH_EVENT,
+ ASSOC_EVENT,
+ DEAUTH_RX_EVENT,
+ DEAUTH_TX_EVENT,
+};
+
+/**
+ * enum ieee80211_mlme_event_status - relevant when event type is %MLME_EVENT
+ * @MLME_SUCCESS: the MLME operation completed successfully.
+ * @MLME_DENIED: the MLME operation was denied by the peer.
+ * @MLME_TIMEOUT: the MLME operation timed out.
+ */
+enum ieee80211_mlme_event_status {
+ MLME_SUCCESS,
+ MLME_DENIED,
+ MLME_TIMEOUT,
+};
+
+/**
+ * enum 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
+ */
+struct ieee80211_mlme_event {
+ enum ieee80211_mlme_event_data data;
+ enum ieee80211_mlme_event_status status;
+ u16 reason;
+};
+
+/**
+ * struct ieee80211_event - event to be sent to the driver
+ * @type The event itself. See &enum ieee80211_event_type.
+ * @rssi: relevant if &type is %RSSI_EVENT
+ * @mlme: relevant if &type is %AUTH_EVENT
+ */
+struct ieee80211_event {
+ enum ieee80211_event_type type;
+ union {
+ struct ieee80211_rssi_event rssi;
+ struct ieee80211_mlme_event mlme;
+ } u;
+};
+
+/**
* struct ieee80211_bss_conf - holds the BSS's changing parameters
*
* This structure keeps information about a BSS (and an association
@@ -337,12 +406,15 @@ enum ieee80211_rssi_event {
* HW flag %IEEE80211_HW_TIMING_BEACON_ONLY is set, then this can
* only come from a beacon, but might not become valid until after
* association when a beacon is received (which is notified with the
- * %BSS_CHANGED_DTIM flag.)
+ * %BSS_CHANGED_DTIM flag.). See also sync_dtim_count important notice.
* @sync_device_ts: the device timestamp corresponding to the sync_tsf,
* the driver/device can use this to calculate synchronisation
- * (see @sync_tsf)
+ * (see @sync_tsf). See also sync_dtim_count important notice.
* @sync_dtim_count: Only valid when %IEEE80211_HW_TIMING_BEACON_ONLY
* is requested, see @sync_tsf/@sync_device_ts.
+ * IMPORTANT: These three sync_* parameters would possibly be out of sync
+ * by the time the driver will use them. The synchronized view is currently
+ * guaranteed only in certain callbacks.
* @beacon_int: beacon interval
* @assoc_capability: capabilities taken from assoc resp
* @basic_rates: bitmap of basic rates, each bit stands for an
@@ -1279,6 +1351,19 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
/**
+ * ieee80211_vif_to_wdev - return a wdev struct from a vif
+ * @vif: the vif to get the wdev for
+ *
+ * This can be used by mac80211 drivers with direct cfg80211 APIs
+ * (like the vendor commands) that needs to get the wdev for a vif.
+ *
+ * Note that this function may return %NULL if the given wdev isn't
+ * associated with a vif that the driver knows about (e.g. monitor
+ * or AP_VLAN interfaces.)
+ */
+struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif);
+
+/**
* enum ieee80211_key_flags - key flags
*
* These flags are used for communication about keys between the driver
@@ -1472,7 +1557,8 @@ struct ieee80211_sta_rates {
* @supp_rates: Bitmap of supported rates (per band)
* @ht_cap: HT capabilities of this STA; restricted to our own capabilities
* @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
- * @wme: indicates whether the STA supports QoS/WME.
+ * @wme: indicates whether the STA supports QoS/WME (if local devices does,
+ * otherwise always false)
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *), size is determined in hw information.
* @uapsd_queues: bitmap of queues configured for uapsd. Only valid
@@ -1488,6 +1574,7 @@ struct ieee80211_sta_rates {
* @tdls: indicates whether the STA is a TDLS peer
* @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only
* valid if the STA is a TDLS peer in the first place.
+ * @mfp: indicates whether the STA uses management frame protection or not.
*/
struct ieee80211_sta {
u32 supp_rates[IEEE80211_NUM_BANDS];
@@ -1504,6 +1591,7 @@ struct ieee80211_sta {
struct ieee80211_sta_rates __rcu *rates;
bool tdls;
bool tdls_initiator;
+ bool mfp;
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
@@ -2844,8 +2932,9 @@ enum ieee80211_reconfig_type {
* @set_bitrate_mask: Set a mask of rates to be used for rate control selection
* when transmitting a frame. Currently only legacy rates are handled.
* The callback can sleep.
- * @rssi_callback: Notify driver when the average RSSI goes above/below
- * thresholds that were registered previously. 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.
*
* @release_buffered_frames: Release buffered frames according to the given
* parameters. In the case where the driver buffers some frames for
@@ -3141,9 +3230,9 @@ struct ieee80211_ops {
bool (*tx_frames_pending)(struct ieee80211_hw *hw);
int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask);
- void (*rssi_callback)(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum ieee80211_rssi_event rssi_event);
+ void (*event_callback)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const struct ieee80211_event *event);
void (*allow_buffered_frames)(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
@@ -4343,13 +4432,33 @@ void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);
* haven't been re-added to the driver yet.
* @IEEE80211_IFACE_ITER_RESUME_ALL: During resume, iterate over all
* interfaces, even if they haven't been re-added to the driver yet.
+ * @IEEE80211_IFACE_ITER_ACTIVE: Iterate only active interfaces (netdev is up).
*/
enum ieee80211_interface_iteration_flags {
IEEE80211_IFACE_ITER_NORMAL = 0,
IEEE80211_IFACE_ITER_RESUME_ALL = BIT(0),
+ IEEE80211_IFACE_ITER_ACTIVE = BIT(1),
};
/**
+ * ieee80211_iterate_interfaces - iterate interfaces
+ *
+ * This function iterates over the interfaces associated with a given
+ * hardware and calls the callback for them. This includes active as well as
+ * inactive interfaces. This function allows the iterator function to sleep.
+ * Will iterate over a new interface during add_interface().
+ *
+ * @hw: the hardware struct of which the interfaces should be iterated over
+ * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags
+ * @iterator: the iterator function to call
+ * @data: first argument of the iterator function
+ */
+void ieee80211_iterate_interfaces(struct ieee80211_hw *hw, u32 iter_flags,
+ void (*iterator)(void *data, u8 *mac,
+ struct ieee80211_vif *vif),
+ void *data);
+
+/**
* ieee80211_iterate_active_interfaces - iterate active interfaces
*
* This function iterates over the interfaces associated with a given
@@ -4364,11 +4473,16 @@ enum ieee80211_interface_iteration_flags {
* @iterator: the iterator function to call
* @data: first argument of the iterator function
*/
-void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,
- u32 iter_flags,
- void (*iterator)(void *data, u8 *mac,
- struct ieee80211_vif *vif),
- void *data);
+static inline void
+ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, u32 iter_flags,
+ void (*iterator)(void *data, u8 *mac,
+ struct ieee80211_vif *vif),
+ void *data)
+{
+ ieee80211_iterate_interfaces(hw,
+ iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
+ iterator, data);
+}
/**
* ieee80211_iterate_active_interfaces_atomic - iterate active interfaces
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 68b294e83944..241220c43e86 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -25,6 +25,19 @@
*
*/
+/*
+ * This header file defines the userspace API to the wireless stack. Please
+ * be careful not to break things - i.e. don't move anything around or so
+ * unless you can demonstrate that it breaks neither API nor ABI.
+ *
+ * Additions to the API should be accompanied by actual implementations in
+ * an upstream driver, so that example implementations exist in case there
+ * are ever concerns about the precise semantics of the API or changes are
+ * needed, and to ensure that code for dead (no longer implemented) API
+ * can actually be identified and removed.
+ * Nonetheless, semantics should also be documented carefully in this file.
+ */
+
#include <linux/types.h>
#define NL80211_GENL_NAME "nl80211"
@@ -1684,6 +1697,10 @@ enum nl80211_commands {
* If set during scheduled scan start then the new scan req will be
* owned by the netlink socket that created it and the scheduled scan will
* be stopped when the socket is closed.
+ * If set during configuration of regulatory indoor operation then the
+ * regulatory indoor configuration would be owned by the netlink socket
+ * that configured the indoor setting, and the indoor operation would be
+ * cleared when the socket is closed.
*
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
* the TDLS link initiator.
@@ -1737,8 +1754,12 @@ enum nl80211_commands {
* should be contained in the result as the sum of the respective counters
* over all channels.
*
- * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a
- * WoWLAN net-detect scan) is started, u32 in seconds.
+ * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before the first cycle of a
+ * scheduled scan (or a WoWLAN net-detect scan) is started, u32
+ * in seconds.
+
+ * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
+ * is operating in an indoor environment.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2107,6 +2128,8 @@ enum nl80211_attrs {
NL80211_ATTR_SCHED_SCAN_DELAY,
+ NL80211_ATTR_REG_INDOOR,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3092,7 +3115,8 @@ enum nl80211_mesh_power_mode {
*
* @NL80211_MESHCONF_PLINK_TIMEOUT: If no tx activity is seen from a STA we've
* established peering with for longer than this time (in seconds), then
- * remove it from the STA's list of peers. Default is 30 minutes.
+ * remove it from the STA's list of peers. You may set this to 0 to disable
+ * the removal of the STA. Default is 30 minutes.
*
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
*/
@@ -3694,6 +3718,8 @@ struct nl80211_pattern_support {
* @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
* the chip into a special state -- works best with chips that have
* support for low-power operation already (flag)
+ * Note that this mode is incompatible with all of the others, if
+ * any others are even supported by the device.
* @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
* is detected is implementation-specific (flag)
* @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
@@ -4327,11 +4353,13 @@ enum nl80211_feature_flags {
/**
* enum nl80211_ext_feature_index - bit index of extended features.
+ * @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
enum nl80211_ext_feature_index {
+ NL80211_EXT_FEATURE_VHT_IBSS,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 27649e85f3f6..090828cf1fa7 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -592,15 +592,16 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv,
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
- ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n",
- (curr_gw == gw_node ? "=>" : " "),
- gw_node->orig_node->orig,
- router_ifinfo->bat_iv.tq_avg, router->addr,
- router->if_incoming->net_dev->name,
- gw_node->bandwidth_down / 10,
- gw_node->bandwidth_down % 10,
- gw_node->bandwidth_up / 10,
- gw_node->bandwidth_up % 10);
+ seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n",
+ (curr_gw == gw_node ? "=>" : " "),
+ gw_node->orig_node->orig,
+ router_ifinfo->bat_iv.tq_avg, router->addr,
+ router->if_incoming->net_dev->name,
+ gw_node->bandwidth_down / 10,
+ gw_node->bandwidth_down % 10,
+ gw_node->bandwidth_up / 10,
+ gw_node->bandwidth_up % 10);
+ ret = seq_has_overflowed(seq) ? -1 : 0;
if (curr_gw)
batadv_gw_node_free_ref(curr_gw);
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 4fbcea0e7ecb..17e0177467f5 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -22,6 +22,24 @@
#include "br_private.h"
#include "br_private_stp.h"
+static size_t br_get_link_af_size(const struct net_device *dev)
+{
+ struct net_port_vlans *pv;
+
+ if (br_port_exists(dev))
+ pv = nbp_get_vlan_info(br_port_get_rtnl(dev));
+ else if (dev->priv_flags & IFF_EBRIDGE)
+ pv = br_get_vlan_info((struct net_bridge *)netdev_priv(dev));
+ else
+ return 0;
+
+ if (!pv)
+ return 0;
+
+ /* Each VLAN is returned in bridge_vlan_info along with flags */
+ return pv->num_vlans * nla_total_size(sizeof(struct bridge_vlan_info));
+}
+
static inline size_t br_port_info_size(void)
{
return nla_total_size(1) /* IFLA_BRPORT_STATE */
@@ -36,7 +54,7 @@ static inline size_t br_port_info_size(void)
+ 0;
}
-static inline size_t br_nlmsg_size(void)
+static inline size_t br_nlmsg_size(struct net_device *dev)
{
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
+ nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
@@ -45,7 +63,8 @@ static inline size_t br_nlmsg_size(void)
+ nla_total_size(4) /* IFLA_MTU */
+ nla_total_size(4) /* IFLA_LINK */
+ nla_total_size(1) /* IFLA_OPERSTATE */
- + nla_total_size(br_port_info_size()); /* IFLA_PROTINFO */
+ + nla_total_size(br_port_info_size()) /* IFLA_PROTINFO */
+ + nla_total_size(br_get_link_af_size(dev)); /* IFLA_AF_SPEC */
}
static int br_port_fill_attrs(struct sk_buff *skb,
@@ -288,11 +307,12 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
br_debug(port->br, "port %u(%s) event %d\n",
(unsigned int)port->port_no, port->dev->name, event);
- skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC);
+ skb = nlmsg_new(br_nlmsg_size(port->dev), GFP_ATOMIC);
if (skb == NULL)
goto errout;
- err = br_fill_ifinfo(skb, port, 0, 0, event, 0, 0, port->dev);
+ err = br_fill_ifinfo(skb, port, 0, 0, event, 0,
+ RTEXT_FILTER_BRVLAN_COMPRESSED, port->dev);
if (err < 0) {
/* -EMSGSIZE implies BUG in br_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
@@ -703,24 +723,6 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev)
return 0;
}
-static size_t br_get_link_af_size(const struct net_device *dev)
-{
- struct net_port_vlans *pv;
-
- if (br_port_exists(dev))
- pv = nbp_get_vlan_info(br_port_get_rtnl(dev));
- else if (dev->priv_flags & IFF_EBRIDGE)
- pv = br_get_vlan_info((struct net_bridge *)netdev_priv(dev));
- else
- return 0;
-
- if (!pv)
- return 0;
-
- /* Each VLAN is returned in bridge_vlan_info along with flags */
- return pv->num_vlans * nla_total_size(sizeof(struct bridge_vlan_info));
-}
-
static struct rtnl_af_ops br_af_ops __read_mostly = {
.family = AF_BRIDGE,
.get_link_af_size = br_get_link_af_size,
diff --git a/net/compat.c b/net/compat.c
index 3236b4167a32..49c6a8fb9f09 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -508,25 +508,25 @@ COMPAT_SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
struct compat_group_req {
__u32 gr_interface;
struct __kernel_sockaddr_storage gr_group
- __attribute__ ((aligned(4)));
+ __aligned(4);
} __packed;
struct compat_group_source_req {
__u32 gsr_interface;
struct __kernel_sockaddr_storage gsr_group
- __attribute__ ((aligned(4)));
+ __aligned(4);
struct __kernel_sockaddr_storage gsr_source
- __attribute__ ((aligned(4)));
+ __aligned(4);
} __packed;
struct compat_group_filter {
__u32 gf_interface;
struct __kernel_sockaddr_storage gf_group
- __attribute__ ((aligned(4)));
+ __aligned(4);
__u32 gf_fmode;
__u32 gf_numsrc;
struct __kernel_sockaddr_storage gf_slist[1]
- __attribute__ ((aligned(4)));
+ __aligned(4);
} __packed;
#define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 91f74f3eb204..eb0c3ace7458 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -789,7 +789,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
if (ops->get_rxfh_indir_size)
dev_indir_size = ops->get_rxfh_indir_size(dev);
if (ops->get_rxfh_key_size)
- dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev);
+ dev_key_size = ops->get_rxfh_key_size(dev);
if (copy_from_user(&rxfh, useraddr, sizeof(rxfh)))
return -EFAULT;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 88c613eab142..374e43bc6b80 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2865,7 +2865,6 @@ static void skb_ts_finish(struct ts_config *conf, struct ts_state *state)
* @from: search offset
* @to: search limit
* @config: textsearch configuration
- * @state: uninitialized textsearch state variable
*
* Finds a pattern in the skb data according to the specified
* textsearch configuration. Use textsearch_next() to retrieve
@@ -2873,17 +2872,17 @@ static void skb_ts_finish(struct ts_config *conf, struct ts_state *state)
* to the first occurrence or UINT_MAX if no match was found.
*/
unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
- unsigned int to, struct ts_config *config,
- struct ts_state *state)
+ unsigned int to, struct ts_config *config)
{
+ struct ts_state state;
unsigned int ret;
config->get_next_block = skb_ts_get_next_block;
config->finish = skb_ts_finish;
- skb_prepare_seq_read(skb, from, to, TS_SKB_CB(state));
+ skb_prepare_seq_read(skb, from, to, TS_SKB_CB(&state));
- ret = textsearch_find(config, state);
+ ret = textsearch_find(config, &state);
return (ret <= to - from ? ret : UINT_MAX);
}
EXPORT_SYMBOL(skb_find_text);
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 666cf364df86..4b1172d73e03 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1849,30 +1849,25 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc)
pmc->sfcount[MCAST_EXCLUDE] = 1;
}
-
-/*
- * Join a multicast group
- */
-int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
+int __ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr)
{
- int err;
__be32 addr = imr->imr_multiaddr.s_addr;
- struct ip_mc_socklist *iml = NULL, *i;
+ struct ip_mc_socklist *iml, *i;
struct in_device *in_dev;
struct inet_sock *inet = inet_sk(sk);
struct net *net = sock_net(sk);
int ifindex;
int count = 0;
+ int err;
+
+ ASSERT_RTNL();
if (!ipv4_is_multicast(addr))
return -EINVAL;
- rtnl_lock();
-
in_dev = ip_mc_find_dev(net, imr);
if (!in_dev) {
- iml = NULL;
err = -ENODEV;
goto done;
}
@@ -1900,9 +1895,22 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
ip_mc_inc_group(in_dev, addr);
err = 0;
done:
- rtnl_unlock();
return err;
}
+EXPORT_SYMBOL(__ip_mc_join_group);
+
+/* Join a multicast group
+ */
+int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr)
+{
+ int ret;
+
+ rtnl_lock();
+ ret = __ip_mc_join_group(sk, imr);
+ rtnl_unlock();
+
+ return ret;
+}
EXPORT_SYMBOL(ip_mc_join_group);
static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
@@ -1925,11 +1933,7 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
return err;
}
-/*
- * Ask a socket to leave a group.
- */
-
-int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
+int __ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
{
struct inet_sock *inet = inet_sk(sk);
struct ip_mc_socklist *iml;
@@ -1940,7 +1944,8 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
u32 ifindex;
int ret = -EADDRNOTAVAIL;
- rtnl_lock();
+ ASSERT_RTNL();
+
in_dev = ip_mc_find_dev(net, imr);
if (!in_dev) {
ret = -ENODEV;
@@ -1964,14 +1969,25 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
*imlp = iml->next_rcu;
ip_mc_dec_group(in_dev, group);
- rtnl_unlock();
+
/* decrease mem now to avoid the memleak warning */
atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
kfree_rcu(iml, rcu);
return 0;
}
out:
+ return ret;
+}
+EXPORT_SYMBOL(__ip_mc_leave_group);
+
+int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
+{
+ int ret;
+
+ rtnl_lock();
+ ret = __ip_mc_leave_group(sk, imr);
rtnl_unlock();
+
return ret;
}
EXPORT_SYMBOL(ip_mc_leave_group);
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index d694088214cd..d4c3a5e66380 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -83,7 +83,7 @@ int tcp_register_congestion_control(struct tcp_congestion_ops *ca)
ret = -EEXIST;
} else {
list_add_tail_rcu(&ca->list, &tcp_cong_list);
- pr_info("%s registered\n", ca->name);
+ pr_debug("%s registered\n", ca->name);
}
spin_unlock(&tcp_cong_list_lock);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index dae7f1a1e464..0d84b2c7f24e 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -32,7 +32,7 @@
#include <linux/netfilter_ipv6.h>
#include <linux/skbuff.h>
#include <linux/compat.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/ioctls.h>
#include <net/net_namespace.h>
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
index 7869bb40acaa..208df7c0b6ea 100644
--- a/net/mac80211/aes_ccm.c
+++ b/net/mac80211/aes_ccm.c
@@ -85,11 +85,15 @@ struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
return tfm;
err = crypto_aead_setkey(tfm, key, key_len);
- if (!err)
- err = crypto_aead_setauthsize(tfm, mic_len);
- if (!err)
- return tfm;
+ if (err)
+ goto free_aead;
+ err = crypto_aead_setauthsize(tfm, mic_len);
+ if (err)
+ goto free_aead;
+
+ return tfm;
+free_aead:
crypto_free_aead(tfm);
return ERR_PTR(err);
}
diff --git a/net/mac80211/aes_gcm.c b/net/mac80211/aes_gcm.c
index c2bf6698d738..fd278bbe1b0d 100644
--- a/net/mac80211/aes_gcm.c
+++ b/net/mac80211/aes_gcm.c
@@ -80,11 +80,15 @@ struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
return tfm;
err = crypto_aead_setkey(tfm, key, key_len);
- if (!err)
- err = crypto_aead_setauthsize(tfm, IEEE80211_GCMP_MIC_LEN);
- if (!err)
- return tfm;
+ if (err)
+ goto free_aead;
+ err = crypto_aead_setauthsize(tfm, IEEE80211_GCMP_MIC_LEN);
+ if (err)
+ goto free_aead;
+
+ return tfm;
+free_aead:
crypto_free_aead(tfm);
return ERR_PTR(err);
}
diff --git a/net/mac80211/aes_gmac.c b/net/mac80211/aes_gmac.c
index 1c72edcb0083..f1321b7d6506 100644
--- a/net/mac80211/aes_gmac.c
+++ b/net/mac80211/aes_gmac.c
@@ -70,9 +70,9 @@ struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[],
err = crypto_aead_setkey(tfm, key, key_len);
if (!err)
- return tfm;
- if (!err)
err = crypto_aead_setauthsize(tfm, GMAC_MIC_LEN);
+ if (!err)
+ return tfm;
crypto_free_aead(tfm);
return ERR_PTR(err);
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index a48bad468880..2c090c507391 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -234,6 +234,14 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
int i, ret = -EOPNOTSUPP;
u16 status = WLAN_STATUS_REQUEST_DECLINED;
+ if (!sta->sta.ht_cap.ht_supported) {
+ ht_dbg(sta->sdata,
+ "STA %pM erroneously requests BA session on tid %d w/o QoS\n",
+ sta->sta.addr, tid);
+ /* send a response anyway, it's an error case if we get here */
+ goto end_no_lock;
+ }
+
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
ht_dbg(sta->sdata,
"Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index a360c15cc978..20522492d8cc 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -509,11 +509,14 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
struct tid_ampdu_tx *tid_tx;
int ret = 0;
+ trace_api_start_tx_ba_session(pubsta, tid);
+
if (WARN(sta->reserved_tid == tid,
"Requested to start BA session on reserved tid=%d", tid))
return -EINVAL;
- trace_api_start_tx_ba_session(pubsta, tid);
+ if (!pubsta->ht_cap.ht_supported)
+ return -EINVAL;
if (WARN_ON_ONCE(!local->ops->ampdu_action))
return -EINVAL;
@@ -793,6 +796,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
struct tid_ampdu_tx *tid_tx;
+ bool send_delba = false;
trace_api_stop_tx_ba_cb(sdata, ra, tid);
@@ -824,13 +828,17 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
}
if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR && tid_tx->tx_stop)
- ieee80211_send_delba(sta->sdata, ra, tid,
- WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
+ send_delba = true;
ieee80211_remove_tid_tx(sta, tid);
unlock_sta:
spin_unlock_bh(&sta->lock);
+
+ if (send_delba)
+ ieee80211_send_delba(sdata, ra, tid,
+ WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
+
mutex_unlock(&sta->ampdu_mlme.mtx);
unlock:
mutex_unlock(&local->sta_mtx);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index dd4ff36c557a..e4dd2fc34de3 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -24,6 +24,7 @@
static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
const char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type,
u32 *flags,
struct vif_params *params)
@@ -33,7 +34,7 @@ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
struct ieee80211_sub_if_data *sdata;
int err;
- err = ieee80211_if_add(local, name, &wdev, type, params);
+ err = ieee80211_if_add(local, name, name_assign_type, &wdev, type, params);
if (err)
return ERR_PTR(err);
@@ -977,6 +978,14 @@ static int sta_apply_auth_flags(struct ieee80211_local *local,
if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
set & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
!test_sta_flag(sta, WLAN_STA_ASSOC)) {
+ /*
+ * When peer becomes associated, init rate control as
+ * well. Some drivers require rate control initialized
+ * before drv_sta_state() is called.
+ */
+ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+ rate_control_rate_init(sta);
+
ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
if (ret)
return ret;
@@ -1050,6 +1059,10 @@ static int sta_apply_parameters(struct ieee80211_local *local,
}
}
+ if (mask & BIT(NL80211_STA_FLAG_WME) &&
+ local->hw.queues >= IEEE80211_NUM_ACS)
+ sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
+
/* auth flags will be set later for TDLS stations */
if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
ret = sta_apply_auth_flags(local, sta, mask, set);
@@ -1064,10 +1077,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
}
- if (mask & BIT(NL80211_STA_FLAG_WME))
- sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
-
if (mask & BIT(NL80211_STA_FLAG_MFP)) {
+ sta->sta.mfp = !!(set & BIT(NL80211_STA_FLAG_MFP));
if (set & BIT(NL80211_STA_FLAG_MFP))
set_sta_flag(sta, WLAN_STA_MFP);
else
@@ -1377,11 +1388,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
if (err)
goto out_err;
- /* When peer becomes authorized, init rate control as well */
- if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
- test_sta_flag(sta, WLAN_STA_AUTHORIZED))
- rate_control_rate_init(sta);
-
mutex_unlock(&local->sta_mtx);
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
@@ -2273,7 +2279,6 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
{
struct sta_info *sta;
enum ieee80211_smps_mode old_req;
- int i;
if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP))
return -EINVAL;
@@ -2297,52 +2302,44 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
}
ht_dbg(sdata,
- "SMSP %d requested in AP mode, sending Action frame to %d stations\n",
+ "SMPS %d requested in AP mode, sending Action frame to %d stations\n",
smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta));
mutex_lock(&sdata->local->sta_mtx);
- for (i = 0; i < STA_HASH_SIZE; i++) {
- for (sta = rcu_dereference_protected(sdata->local->sta_hash[i],
- lockdep_is_held(&sdata->local->sta_mtx));
- sta;
- sta = rcu_dereference_protected(sta->hnext,
- lockdep_is_held(&sdata->local->sta_mtx))) {
- /*
- * Only stations associated to our AP and
- * associated VLANs
- */
- if (sta->sdata->bss != &sdata->u.ap)
- continue;
+ list_for_each_entry(sta, &sdata->local->sta_list, list) {
+ /*
+ * Only stations associated to our AP and
+ * associated VLANs
+ */
+ if (sta->sdata->bss != &sdata->u.ap)
+ continue;
- /* This station doesn't support MIMO - skip it */
- if (sta_info_tx_streams(sta) == 1)
- continue;
+ /* This station doesn't support MIMO - skip it */
+ if (sta_info_tx_streams(sta) == 1)
+ continue;
- /*
- * Don't wake up a STA just to send the action frame
- * unless we are getting more restrictive.
- */
- if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
- !ieee80211_smps_is_restrictive(sta->known_smps_mode,
- smps_mode)) {
- ht_dbg(sdata,
- "Won't send SMPS to sleeping STA %pM\n",
- sta->sta.addr);
- continue;
- }
+ /*
+ * Don't wake up a STA just to send the action frame
+ * unless we are getting more restrictive.
+ */
+ if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
+ !ieee80211_smps_is_restrictive(sta->known_smps_mode,
+ smps_mode)) {
+ ht_dbg(sdata, "Won't send SMPS to sleeping STA %pM\n",
+ sta->sta.addr);
+ continue;
+ }
- /*
- * If the STA is not authorized, wait until it gets
- * authorized and the action frame will be sent then.
- */
- if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
- continue;
+ /*
+ * If the STA is not authorized, wait until it gets
+ * authorized and the action frame will be sent then.
+ */
+ if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ continue;
- ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr);
- ieee80211_send_smps_action(sdata, smps_mode,
- sta->sta.addr,
- sdata->vif.bss_conf.bssid);
- }
+ ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr);
+ ieee80211_send_smps_action(sdata, smps_mode, sta->sta.addr,
+ sdata->vif.bss_conf.bssid);
}
mutex_unlock(&sdata->local->sta_mtx);
@@ -3581,7 +3578,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
nullfunc->qos_ctrl = cpu_to_le16(7);
local_bh_disable();
- ieee80211_xmit(sdata, skb);
+ ieee80211_xmit(sdata, sta, skb);
local_bh_enable();
rcu_read_unlock();
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index eeb0bbd69d98..23813ebb349c 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -18,172 +18,6 @@
#define DEBUGFS_FORMAT_BUFFER_SIZE 100
-#define TX_LATENCY_BIN_DELIMTER_C ','
-#define TX_LATENCY_BIN_DELIMTER_S ","
-#define TX_LATENCY_BINS_DISABLED "enable(bins disabled)\n"
-#define TX_LATENCY_DISABLED "disable\n"
-
-
-/*
- * Display if Tx latency statistics & bins are enabled/disabled
- */
-static ssize_t sta_tx_latency_stat_read(struct file *file,
- char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- struct ieee80211_tx_latency_bin_ranges *tx_latency;
- char *buf;
- int bufsz, i, ret;
- int pos = 0;
-
- rcu_read_lock();
-
- tx_latency = rcu_dereference(local->tx_latency);
-
- if (tx_latency && tx_latency->n_ranges) {
- bufsz = tx_latency->n_ranges * 15;
- buf = kzalloc(bufsz, GFP_ATOMIC);
- if (!buf)
- goto err;
-
- for (i = 0; i < tx_latency->n_ranges; i++)
- pos += scnprintf(buf + pos, bufsz - pos, "%d,",
- tx_latency->ranges[i]);
- pos += scnprintf(buf + pos, bufsz - pos, "\n");
- } else if (tx_latency) {
- bufsz = sizeof(TX_LATENCY_BINS_DISABLED) + 1;
- buf = kzalloc(bufsz, GFP_ATOMIC);
- if (!buf)
- goto err;
-
- pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
- TX_LATENCY_BINS_DISABLED);
- } else {
- bufsz = sizeof(TX_LATENCY_DISABLED) + 1;
- buf = kzalloc(bufsz, GFP_ATOMIC);
- if (!buf)
- goto err;
-
- pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
- TX_LATENCY_DISABLED);
- }
-
- rcu_read_unlock();
-
- ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
- kfree(buf);
-
- return ret;
-err:
- rcu_read_unlock();
- return -ENOMEM;
-}
-
-/*
- * Receive input from user regarding Tx latency statistics
- * The input should indicate if Tx latency statistics and bins are
- * enabled/disabled.
- * If bins are enabled input should indicate the amount of different bins and
- * their ranges. Each bin will count how many Tx frames transmitted within the
- * appropriate latency.
- * Legal input is:
- * a) "enable(bins disabled)" - to enable only general statistics
- * b) "a,b,c,d,...z" - to enable general statistics and bins, where all are
- * numbers and a < b < c < d.. < z
- * c) "disable" - disable all statistics
- * NOTE: must configure Tx latency statistics bins before stations connected.
- */
-
-static ssize_t sta_tx_latency_stat_write(struct file *file,
- const char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- char buf[128] = {};
- char *bins = buf;
- char *token;
- int buf_size, i, alloc_size;
- int prev_bin = 0;
- int n_ranges = 0;
- int ret = count;
- struct ieee80211_tx_latency_bin_ranges *tx_latency;
-
- if (sizeof(buf) <= count)
- return -EINVAL;
- buf_size = count;
- if (copy_from_user(buf, userbuf, buf_size))
- return -EFAULT;
-
- mutex_lock(&local->sta_mtx);
-
- /* cannot change config once we have stations */
- if (local->num_sta)
- goto unlock;
-
- tx_latency =
- rcu_dereference_protected(local->tx_latency,
- lockdep_is_held(&local->sta_mtx));
-
- /* disable Tx statistics */
- if (!strcmp(buf, TX_LATENCY_DISABLED)) {
- if (!tx_latency)
- goto unlock;
- RCU_INIT_POINTER(local->tx_latency, NULL);
- synchronize_rcu();
- kfree(tx_latency);
- goto unlock;
- }
-
- /* Tx latency already enabled */
- if (tx_latency)
- goto unlock;
-
- if (strcmp(TX_LATENCY_BINS_DISABLED, buf)) {
- /* check how many bins and between what ranges user requested */
- token = buf;
- while (*token != '\0') {
- if (*token == TX_LATENCY_BIN_DELIMTER_C)
- n_ranges++;
- token++;
- }
- n_ranges++;
- }
-
- alloc_size = sizeof(struct ieee80211_tx_latency_bin_ranges) +
- n_ranges * sizeof(u32);
- tx_latency = kzalloc(alloc_size, GFP_ATOMIC);
- if (!tx_latency) {
- ret = -ENOMEM;
- goto unlock;
- }
- tx_latency->n_ranges = n_ranges;
- for (i = 0; i < n_ranges; i++) { /* setting bin ranges */
- token = strsep(&bins, TX_LATENCY_BIN_DELIMTER_S);
- sscanf(token, "%d", &tx_latency->ranges[i]);
- /* bins values should be in ascending order */
- if (prev_bin >= tx_latency->ranges[i]) {
- ret = -EINVAL;
- kfree(tx_latency);
- goto unlock;
- }
- prev_bin = tx_latency->ranges[i];
- }
- rcu_assign_pointer(local->tx_latency, tx_latency);
-
-unlock:
- mutex_unlock(&local->sta_mtx);
-
- return ret;
-}
-
-static const struct file_operations stats_tx_latency_ops = {
- .write = sta_tx_latency_stat_write,
- .read = sta_tx_latency_stat_read,
- .open = simple_open,
- .llseek = generic_file_llseek,
-};
-
int mac80211_format_buffer(char __user *userbuf, size_t count,
loff_t *ppos, char *fmt, ...)
{
@@ -440,8 +274,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
#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_unencrypted,
- local->tx_handlers_drop_unencrypted);
DEBUGFS_STATS_ADD(tx_handlers_drop_fragment,
local->tx_handlers_drop_fragment);
DEBUGFS_STATS_ADD(tx_handlers_drop_wep,
@@ -475,6 +307,4 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
-
- DEBUGFS_DEVSTATS_ADD(tx_latency);
}
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index c68896adfa96..29236e832e44 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -177,7 +177,6 @@ static ssize_t ieee80211_if_write_##name(struct file *file, \
IEEE80211_IF_FILE_R(name)
/* common attributes */
-IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ],
HEX);
IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
@@ -562,7 +561,6 @@ IEEE80211_IF_FILE(dot11MeshAwakeWindowDuration,
static void add_common_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(drop_unencrypted);
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 94c70091bbd7..252859e90e8a 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -39,13 +39,6 @@ static const struct file_operations sta_ ##name## _ops = { \
.llseek = generic_file_llseek, \
}
-#define STA_OPS_W(name) \
-static const struct file_operations sta_ ##name## _ops = { \
- .write = sta_##name##_write, \
- .open = simple_open, \
- .llseek = generic_file_llseek, \
-}
-
#define STA_OPS_RW(name) \
static const struct file_operations sta_ ##name## _ops = { \
.read = sta_##name##_read, \
@@ -398,131 +391,6 @@ static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf,
}
STA_OPS(last_rx_rate);
-static int
-sta_tx_latency_stat_header(struct ieee80211_tx_latency_bin_ranges *tx_latency,
- char *buf, int pos, int bufsz)
-{
- int i;
- int range_count = tx_latency->n_ranges;
- u32 *bin_ranges = tx_latency->ranges;
-
- pos += scnprintf(buf + pos, bufsz - pos,
- "Station\t\t\tTID\tMax\tAvg");
- if (range_count) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "\t<=%d", bin_ranges[0]);
- for (i = 0; i < range_count - 1; i++)
- pos += scnprintf(buf + pos, bufsz - pos, "\t%d-%d",
- bin_ranges[i], bin_ranges[i+1]);
- pos += scnprintf(buf + pos, bufsz - pos,
- "\t%d<", bin_ranges[range_count - 1]);
- }
-
- pos += scnprintf(buf + pos, bufsz - pos, "\n");
-
- return pos;
-}
-
-static int
-sta_tx_latency_stat_table(struct ieee80211_tx_latency_bin_ranges *tx_lat_range,
- struct ieee80211_tx_latency_stat *tx_lat,
- char *buf, int pos, int bufsz, int tid)
-{
- u32 avg = 0;
- int j;
- int bin_count = tx_lat->bin_count;
-
- pos += scnprintf(buf + pos, bufsz - pos, "\t\t\t%d", tid);
- /* make sure you don't divide in 0 */
- if (tx_lat->counter)
- avg = tx_lat->sum / tx_lat->counter;
-
- pos += scnprintf(buf + pos, bufsz - pos, "\t%d\t%d",
- tx_lat->max, avg);
-
- if (tx_lat_range->n_ranges && tx_lat->bins)
- for (j = 0; j < bin_count; j++)
- pos += scnprintf(buf + pos, bufsz - pos,
- "\t%d", tx_lat->bins[j]);
- pos += scnprintf(buf + pos, bufsz - pos, "\n");
-
- return pos;
-}
-
-/*
- * Output Tx latency statistics station && restart all statistics information
- */
-static ssize_t sta_tx_latency_stat_read(struct file *file,
- char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct sta_info *sta = file->private_data;
- struct ieee80211_local *local = sta->local;
- struct ieee80211_tx_latency_bin_ranges *tx_latency;
- char *buf;
- int bufsz, ret, i;
- int pos = 0;
-
- bufsz = 20 * IEEE80211_NUM_TIDS *
- sizeof(struct ieee80211_tx_latency_stat);
- buf = kzalloc(bufsz, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- rcu_read_lock();
-
- tx_latency = rcu_dereference(local->tx_latency);
-
- if (!sta->tx_lat) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "Tx latency statistics are not enabled\n");
- goto unlock;
- }
-
- pos = sta_tx_latency_stat_header(tx_latency, buf, pos, bufsz);
-
- pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", sta->sta.addr);
- for (i = 0; i < IEEE80211_NUM_TIDS; i++)
- pos = sta_tx_latency_stat_table(tx_latency, &sta->tx_lat[i],
- buf, pos, bufsz, i);
-unlock:
- rcu_read_unlock();
-
- ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
- kfree(buf);
-
- return ret;
-}
-STA_OPS(tx_latency_stat);
-
-static ssize_t sta_tx_latency_stat_reset_write(struct file *file,
- const char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- u32 *bins;
- int bin_count;
- struct sta_info *sta = file->private_data;
- int i;
-
- if (!sta->tx_lat)
- return -EINVAL;
-
- for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
- bins = sta->tx_lat[i].bins;
- bin_count = sta->tx_lat[i].bin_count;
-
- sta->tx_lat[i].max = 0;
- sta->tx_lat[i].sum = 0;
- sta->tx_lat[i].counter = 0;
-
- if (bin_count)
- memset(bins, 0, bin_count * sizeof(u32));
- }
-
- return count;
-}
-STA_OPS_W(tx_latency_stat_reset);
-
#define DEBUGFS_ADD(name) \
debugfs_create_file(#name, 0400, \
sta->debugfs.dir, sta, &sta_ ##name## _ops);
@@ -576,8 +444,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD(last_ack_signal);
DEBUGFS_ADD(current_tx_rate);
DEBUGFS_ADD(last_rx_rate);
- DEBUGFS_ADD(tx_latency_stat);
- DEBUGFS_ADD(tx_latency_stat_reset);
DEBUGFS_ADD_COUNTER(rx_packets, rx_packets);
DEBUGFS_ADD_COUNTER(tx_packets, tx_packets);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index fdeda17b8dd2..0a39d3db951a 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -941,13 +941,13 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local,
trace_drv_return_void(local);
}
-static inline void drv_rssi_callback(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- const enum ieee80211_rssi_event event)
+static inline void drv_event_callback(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ const struct ieee80211_event *event)
{
- trace_drv_rssi_callback(local, sdata, event);
- if (local->ops->rssi_callback)
- local->ops->rssi_callback(&local->hw, &sdata->vif, event);
+ trace_drv_event_callback(local, sdata, event);
+ if (local->ops->event_callback)
+ local->ops->event_callback(&local->hw, &sdata->vif, event);
trace_drv_return_void(local);
}
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index ff630be2ca75..7a76ce639d58 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -252,8 +252,6 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
break;
}
- if (bw != sta->sta.bandwidth)
- changed = true;
sta->sta.bandwidth = bw;
sta->cur_max_bandwidth =
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index b606b53a49a7..52d629d5e797 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -188,6 +188,16 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
*/
pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
chandef, 0);
+
+ /* add VHT capability and information IEs */
+ if (chandef->width != NL80211_CHAN_WIDTH_20 &&
+ chandef->width != NL80211_CHAN_WIDTH_40 &&
+ sband->vht_cap.vht_supported) {
+ pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
+ sband->vht_cap.cap);
+ pos = ieee80211_ie_build_vht_oper(pos, &sband->vht_cap,
+ chandef);
+ }
}
if (local->hw.queues >= IEEE80211_NUM_ACS)
@@ -249,8 +259,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
if (presp)
kfree_rcu(presp, rcu_head);
- sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
-
/* make a copy of the chandef, it could be modified below. */
chandef = *req_chandef;
chan = chandef.chan;
@@ -417,6 +425,11 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
NL80211_CHAN_WIDTH_20_NOHT);
chandef.width = sdata->u.ibss.chandef.width;
break;
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_160:
+ chandef = sdata->u.ibss.chandef;
+ chandef.chan = cbss->channel;
+ break;
default:
/* fall back to 20 MHz for unsupported modes */
cfg80211_chandef_create(&chandef, cbss->channel,
@@ -470,22 +483,19 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
struct beacon_data *presp, *old_presp;
struct cfg80211_bss *cbss;
const struct cfg80211_bss_ies *ies;
- u16 capability;
+ u16 capability = 0;
u64 tsf;
int ret = 0;
sdata_assert_lock(sdata);
- capability = WLAN_CAPABILITY_IBSS;
-
if (ifibss->privacy)
- capability |= WLAN_CAPABILITY_PRIVACY;
+ capability = WLAN_CAPABILITY_PRIVACY;
cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan,
ifibss->bssid, ifibss->ssid,
- ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
- WLAN_CAPABILITY_PRIVACY,
- capability);
+ ifibss->ssid_len, IEEE80211_BSS_TYPE_IBSS,
+ IEEE80211_PRIVACY(ifibss->privacy));
if (WARN_ON(!cbss)) {
ret = -EINVAL;
@@ -525,23 +535,17 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct cfg80211_bss *cbss;
int err, changed = 0;
- u16 capability;
sdata_assert_lock(sdata);
/* update cfg80211 bss information with the new channel */
if (!is_zero_ether_addr(ifibss->bssid)) {
- capability = WLAN_CAPABILITY_IBSS;
-
- if (ifibss->privacy)
- capability |= WLAN_CAPABILITY_PRIVACY;
-
cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
ifibss->chandef.chan,
ifibss->bssid, ifibss->ssid,
- ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
- WLAN_CAPABILITY_PRIVACY,
- capability);
+ ifibss->ssid_len,
+ IEEE80211_BSS_TYPE_IBSS,
+ IEEE80211_PRIVACY(ifibss->privacy));
/* XXX: should not really modify cfg80211 data */
if (cbss) {
cbss->channel = sdata->csa_chandef.chan;
@@ -682,19 +686,13 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
struct cfg80211_bss *cbss;
struct beacon_data *presp;
struct sta_info *sta;
- u16 capability;
if (!is_zero_ether_addr(ifibss->bssid)) {
- capability = WLAN_CAPABILITY_IBSS;
-
- if (ifibss->privacy)
- capability |= WLAN_CAPABILITY_PRIVACY;
-
cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
ifibss->bssid, ifibss->ssid,
- ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
- WLAN_CAPABILITY_PRIVACY,
- capability);
+ ifibss->ssid_len,
+ IEEE80211_BSS_TYPE_IBSS,
+ IEEE80211_PRIVACY(ifibss->privacy));
if (cbss) {
cfg80211_unlink_bss(local->hw.wiphy, cbss);
@@ -980,110 +978,140 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0, 0);
}
-static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt, size_t len,
- struct ieee80211_rx_status *rx_status,
- struct ieee802_11_elems *elems)
+static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt, size_t len,
+ struct ieee80211_rx_status *rx_status,
+ struct ieee802_11_elems *elems,
+ struct ieee80211_channel *channel)
{
- struct ieee80211_local *local = sdata->local;
- struct cfg80211_bss *cbss;
- struct ieee80211_bss *bss;
struct sta_info *sta;
- struct ieee80211_channel *channel;
- u64 beacon_timestamp, rx_timestamp;
- u32 supp_rates = 0;
enum ieee80211_band band = rx_status->band;
enum nl80211_bss_scan_width scan_width;
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
bool rates_updated = false;
+ u32 supp_rates = 0;
- channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
- if (!channel)
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
return;
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
- ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid)) {
+ if (!ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid))
+ return;
- rcu_read_lock();
- sta = sta_info_get(sdata, mgmt->sa);
-
- if (elems->supp_rates) {
- supp_rates = ieee80211_sta_get_rates(sdata, elems,
- band, NULL);
- if (sta) {
- u32 prev_rates;
-
- prev_rates = sta->sta.supp_rates[band];
- /* make sure mandatory rates are always added */
- scan_width = NL80211_BSS_CHAN_WIDTH_20;
- if (rx_status->flag & RX_FLAG_5MHZ)
- scan_width = NL80211_BSS_CHAN_WIDTH_5;
- if (rx_status->flag & RX_FLAG_10MHZ)
- scan_width = NL80211_BSS_CHAN_WIDTH_10;
-
- sta->sta.supp_rates[band] = supp_rates |
- ieee80211_mandatory_rates(sband,
- scan_width);
- if (sta->sta.supp_rates[band] != prev_rates) {
- ibss_dbg(sdata,
- "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n",
- sta->sta.addr, prev_rates,
- sta->sta.supp_rates[band]);
- rates_updated = true;
- }
- } else {
- rcu_read_unlock();
- sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
- mgmt->sa, supp_rates);
+ rcu_read_lock();
+ sta = sta_info_get(sdata, mgmt->sa);
+
+ if (elems->supp_rates) {
+ supp_rates = ieee80211_sta_get_rates(sdata, elems,
+ band, NULL);
+ if (sta) {
+ u32 prev_rates;
+
+ prev_rates = sta->sta.supp_rates[band];
+ /* make sure mandatory rates are always added */
+ scan_width = NL80211_BSS_CHAN_WIDTH_20;
+ if (rx_status->flag & RX_FLAG_5MHZ)
+ scan_width = NL80211_BSS_CHAN_WIDTH_5;
+ if (rx_status->flag & RX_FLAG_10MHZ)
+ scan_width = NL80211_BSS_CHAN_WIDTH_10;
+
+ sta->sta.supp_rates[band] = supp_rates |
+ ieee80211_mandatory_rates(sband, scan_width);
+ if (sta->sta.supp_rates[band] != prev_rates) {
+ ibss_dbg(sdata,
+ "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n",
+ sta->sta.addr, prev_rates,
+ sta->sta.supp_rates[band]);
+ rates_updated = true;
}
+ } else {
+ rcu_read_unlock();
+ sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
+ mgmt->sa, supp_rates);
}
+ }
- if (sta && elems->wmm_info)
- sta->sta.wme = true;
-
- if (sta && elems->ht_operation && elems->ht_cap_elem &&
- sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
- sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_5 &&
- sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_10) {
- /* we both use HT */
- struct ieee80211_ht_cap htcap_ie;
- struct cfg80211_chan_def chandef;
-
- ieee80211_ht_oper_to_chandef(channel,
- elems->ht_operation,
- &chandef);
-
- memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
-
- /*
- * fall back to HT20 if we don't use or use
- * the other extension channel
- */
- if (chandef.center_freq1 !=
- sdata->u.ibss.chandef.center_freq1)
- htcap_ie.cap_info &=
- cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-
- rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(
- sdata, sband, &htcap_ie, sta);
+ if (sta && elems->wmm_info && local->hw.queues >= IEEE80211_NUM_ACS)
+ sta->sta.wme = true;
+
+ if (sta && elems->ht_operation && elems->ht_cap_elem &&
+ sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
+ sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_5 &&
+ sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_10) {
+ /* we both use HT */
+ struct ieee80211_ht_cap htcap_ie;
+ struct cfg80211_chan_def chandef;
+ enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;
+
+ ieee80211_ht_oper_to_chandef(channel,
+ elems->ht_operation,
+ &chandef);
+
+ memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
+ rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
+ &htcap_ie,
+ sta);
+
+ if (elems->vht_operation && elems->vht_cap_elem &&
+ sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20 &&
+ sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_40) {
+ /* we both use VHT */
+ struct ieee80211_vht_cap cap_ie;
+ struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;
+
+ ieee80211_vht_oper_to_chandef(channel,
+ elems->vht_operation,
+ &chandef);
+ memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
+ ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
+ &cap_ie, sta);
+ if (memcmp(&cap, &sta->sta.vht_cap, sizeof(cap)))
+ rates_updated |= true;
}
- if (sta && rates_updated) {
- u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
- u8 rx_nss = sta->sta.rx_nss;
+ if (bw != sta->sta.bandwidth)
+ rates_updated |= true;
- /* Force rx_nss recalculation */
- sta->sta.rx_nss = 0;
- rate_control_rate_init(sta);
- if (sta->sta.rx_nss != rx_nss)
- changed |= IEEE80211_RC_NSS_CHANGED;
+ if (!cfg80211_chandef_compatible(&sdata->u.ibss.chandef,
+ &chandef))
+ WARN_ON_ONCE(1);
+ }
- drv_sta_rc_update(local, sdata, &sta->sta, changed);
- }
+ if (sta && rates_updated) {
+ u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
+ u8 rx_nss = sta->sta.rx_nss;
- rcu_read_unlock();
+ /* Force rx_nss recalculation */
+ sta->sta.rx_nss = 0;
+ rate_control_rate_init(sta);
+ if (sta->sta.rx_nss != rx_nss)
+ changed |= IEEE80211_RC_NSS_CHANGED;
+
+ drv_sta_rc_update(local, sdata, &sta->sta, changed);
}
+ rcu_read_unlock();
+}
+
+static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt, size_t len,
+ struct ieee80211_rx_status *rx_status,
+ struct ieee802_11_elems *elems)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct cfg80211_bss *cbss;
+ struct ieee80211_bss *bss;
+ struct ieee80211_channel *channel;
+ u64 beacon_timestamp, rx_timestamp;
+ u32 supp_rates = 0;
+ enum ieee80211_band band = rx_status->band;
+
+ channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
+ if (!channel)
+ return;
+
+ ieee80211_update_sta_info(sdata, mgmt, len, rx_status, elems, channel);
+
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
channel);
if (!bss)
@@ -1273,7 +1301,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len,
- NULL, scan_width);
+ NULL, 0, scan_width);
}
static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
@@ -1304,14 +1332,82 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
if (ifibss->privacy)
capability |= WLAN_CAPABILITY_PRIVACY;
- else
- sdata->drop_unencrypted = 0;
__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
&ifibss->chandef, ifibss->basic_rates,
capability, 0, true);
}
+static unsigned ibss_setup_channels(struct wiphy *wiphy,
+ struct ieee80211_channel **channels,
+ unsigned int channels_max,
+ u32 center_freq, u32 width)
+{
+ struct ieee80211_channel *chan = NULL;
+ unsigned int n_chan = 0;
+ u32 start_freq, end_freq, freq;
+
+ if (width <= 20) {
+ start_freq = center_freq;
+ end_freq = center_freq;
+ } else {
+ start_freq = center_freq - width / 2 + 10;
+ end_freq = center_freq + width / 2 - 10;
+ }
+
+ for (freq = start_freq; freq <= end_freq; freq += 20) {
+ chan = ieee80211_get_channel(wiphy, freq);
+ if (!chan)
+ continue;
+ if (n_chan >= channels_max)
+ return n_chan;
+
+ channels[n_chan] = chan;
+ n_chan++;
+ }
+
+ return n_chan;
+}
+
+static unsigned int
+ieee80211_ibss_setup_scan_channels(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef,
+ struct ieee80211_channel **channels,
+ unsigned int channels_max)
+{
+ unsigned int n_chan = 0;
+ u32 width, cf1, cf2 = 0;
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_40:
+ width = 40;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ cf2 = chandef->center_freq2;
+ /* fall through */
+ case NL80211_CHAN_WIDTH_80:
+ width = 80;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ width = 160;
+ break;
+ default:
+ width = 20;
+ break;
+ }
+
+ cf1 = chandef->center_freq1;
+
+ n_chan = ibss_setup_channels(wiphy, channels, channels_max, cf1, width);
+
+ if (cf2)
+ n_chan += ibss_setup_channels(wiphy, &channels[n_chan],
+ channels_max - n_chan, cf2,
+ width);
+
+ return n_chan;
+}
+
/*
* This function is called with state == IEEE80211_IBSS_MLME_SEARCH
*/
@@ -1325,7 +1421,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
const u8 *bssid = NULL;
enum nl80211_bss_scan_width scan_width;
int active_ibss;
- u16 capability;
sdata_assert_lock(sdata);
@@ -1335,9 +1430,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
if (active_ibss)
return;
- capability = WLAN_CAPABILITY_IBSS;
- if (ifibss->privacy)
- capability |= WLAN_CAPABILITY_PRIVACY;
if (ifibss->fixed_bssid)
bssid = ifibss->bssid;
if (ifibss->fixed_channel)
@@ -1346,8 +1438,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
bssid = ifibss->bssid;
cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid,
ifibss->ssid, ifibss->ssid_len,
- WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY,
- capability);
+ IEEE80211_BSS_TYPE_IBSS,
+ IEEE80211_PRIVACY(ifibss->privacy));
if (cbss) {
struct ieee80211_bss *bss;
@@ -1381,11 +1473,18 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
/* Selected IBSS not found in current scan results - try to scan */
if (time_after(jiffies, ifibss->last_scan_completed +
IEEE80211_SCAN_INTERVAL)) {
+ struct ieee80211_channel *channels[8];
+ unsigned int num;
+
sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
+ num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
+ &ifibss->chandef,
+ channels,
+ ARRAY_SIZE(channels));
scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
ieee80211_request_ibss_scan(sdata, ifibss->ssid,
- ifibss->ssid_len, chan,
+ ifibss->ssid_len, channels, num,
scan_width);
} else {
int interval = IEEE80211_SCAN_INTERVAL;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3afe36824703..81340abb3876 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -818,8 +818,6 @@ struct ieee80211_sub_if_data {
unsigned long state;
- int drop_unencrypted;
-
char name[IFNAMSIZ];
/* Fragment table for host-based reassembly */
@@ -1030,24 +1028,6 @@ struct tpt_led_trigger {
};
#endif
-/*
- * struct ieee80211_tx_latency_bin_ranges - Tx latency statistics bins ranges
- *
- * Measuring Tx latency statistics. Counts how many Tx frames transmitted in a
- * certain latency range (in Milliseconds). Each station that uses these
- * ranges will have bins to count the amount of frames received in that range.
- * The user can configure the ranges via debugfs.
- * If ranges is NULL then Tx latency statistics bins are disabled for all
- * stations.
- *
- * @n_ranges: number of ranges that are taken in account
- * @ranges: the ranges that the user requested or NULL if disabled.
- */
-struct ieee80211_tx_latency_bin_ranges {
- int n_ranges;
- u32 ranges[];
-};
-
/**
* mac80211 scan flags - currently active scan mode
*
@@ -1199,12 +1179,6 @@ struct ieee80211_local {
struct timer_list sta_cleanup;
int sta_generation;
- /*
- * Tx latency statistics parameters for all stations.
- * Can enable via debugfs (NULL when disabled).
- */
- struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency;
-
struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
struct tasklet_struct tx_pending_tasklet;
@@ -1286,7 +1260,6 @@ struct ieee80211_local {
/* TX/RX handler statistics */
unsigned int tx_handlers_drop;
unsigned int tx_handlers_queued;
- unsigned int tx_handlers_drop_unencrypted;
unsigned int tx_handlers_drop_fragment;
unsigned int tx_handlers_drop_wep;
unsigned int tx_handlers_drop_not_assoc;
@@ -1556,7 +1529,8 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata);
void ieee80211_scan_work(struct work_struct *work);
int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
const u8 *ssid, u8 ssid_len,
- struct ieee80211_channel *chan,
+ struct ieee80211_channel **channels,
+ unsigned int n_channels,
enum nl80211_bss_scan_width scan_width);
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
struct cfg80211_scan_request *req);
@@ -1605,6 +1579,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
int ieee80211_iface_init(void);
void ieee80211_iface_exit(void);
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
+ unsigned char name_assign_type,
struct wireless_dev **new_wdev, enum nl80211_iftype type,
struct vif_params *params);
int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
@@ -1772,7 +1747,8 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
gfp_t gfp);
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
bool bss_notify);
-void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta, struct sk_buff *skb);
void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int tid,
@@ -1967,6 +1943,8 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u16 prot_mode);
u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
u32 cap);
+u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
+ const struct cfg80211_chan_def *chandef);
int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
const struct ieee80211_supported_band *sband,
const u8 *srates, int srates_len, u32 *rates);
@@ -1982,6 +1960,9 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
const struct ieee80211_ht_operation *ht_oper,
struct cfg80211_chan_def *chandef);
+void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
+ const struct ieee80211_vht_operation *oper,
+ struct cfg80211_chan_def *chandef);
u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
int __must_check
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 81a27516813e..a0cd97fd0c49 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1508,7 +1508,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
}
/* reset some values that shouldn't be kept across type changes */
- sdata->drop_unencrypted = 0;
if (type == NL80211_IFTYPE_STATION)
sdata->u.mgd.use_4addr = false;
@@ -1649,6 +1648,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
}
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
+ unsigned char name_assign_type,
struct wireless_dev **new_wdev, enum nl80211_iftype type,
struct vif_params *params)
{
@@ -1677,7 +1677,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
txqs = IEEE80211_NUM_ACS;
ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size,
- name, NET_NAME_UNKNOWN,
+ name, name_assign_type,
ieee80211_if_setup, txqs, 1);
if (!ndev)
return -ENOMEM;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 0825d76edcfc..2291cd730091 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -492,6 +492,7 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
for (j = 0; j < len; j++)
key->u.gen.rx_pn[i][j] =
seq[len - j - 1];
+ key->flags |= KEY_FLAG_CIPHER_SCHEME;
}
}
memcpy(key->conf.key, key_data, key_len);
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index d57a9915494f..c5a31835be0e 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -30,10 +30,12 @@ struct sta_info;
* @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present
* in the hardware for TX crypto hardware acceleration.
* @KEY_FLAG_TAINTED: Key is tainted and packets should be dropped.
+ * @KEY_FLAG_CIPHER_SCHEME: This key is for a hardware cipher scheme
*/
enum ieee80211_internal_key_flags {
KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0),
KEY_FLAG_TAINTED = BIT(1),
+ KEY_FLAG_CIPHER_SCHEME = BIT(2),
};
enum ieee80211_internal_tkip_state {
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 5e09d354c5a5..4977967c8b00 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1057,7 +1057,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
/* add one default STA interface if supported */
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) &&
!(hw->flags & IEEE80211_HW_NO_AUTO_VIF)) {
- result = ieee80211_if_add(local, "wlan%d", NULL,
+ result = ieee80211_if_add(local, "wlan%d", NET_NAME_ENUM, NULL,
NL80211_IFTYPE_STATION, NULL);
if (result)
wiphy_warn(local->hw.wiphy,
@@ -1201,8 +1201,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
ieee80211_free_ack_frame, NULL);
idr_destroy(&local->ack_status_frames);
- kfree(rcu_access_pointer(local->tx_latency));
-
sta_info_stop(local);
wiphy_free(local->hw.wiphy);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 0c8b2a77d312..acf441ff9f4a 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -574,7 +574,8 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u32 changed;
- ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
+ if (ifmsh->mshcfg.plink_timeout > 0)
+ ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
mesh_path_expire(sdata);
changed = mesh_accept_plinks_update(sdata);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index b488e1859b18..60d737f144e3 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -17,7 +17,7 @@
#define PLINK_GET_PLID(p) (p + 4)
#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
- jiffies + HZ * t / 1000))
+ jiffies + msecs_to_jiffies(t)))
enum plink_event {
PLINK_UNDEFINED,
@@ -382,6 +382,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
struct ieee80211_supported_band *sband;
u32 rates, basic_rates = 0, changed = 0;
+ enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;
sband = local->hw.wiphy->bands[band];
rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates);
@@ -401,6 +402,9 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
elems->ht_cap_elem, sta))
changed |= IEEE80211_RC_BW_CHANGED;
+ if (bw != sta->sta.bandwidth)
+ changed |= IEEE80211_RC_BW_CHANGED;
+
/* HT peer is operating 20MHz-only */
if (elems->ht_operation &&
!(elems->ht_operation->ht_param &
@@ -621,9 +625,9 @@ static void mesh_plink_timer(unsigned long data)
sta->llid, sta->plid, reason);
}
-static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
+static inline void mesh_plink_timer_set(struct sta_info *sta, u32 timeout)
{
- sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
+ sta->plink_timer.expires = jiffies + msecs_to_jiffies(timeout);
sta->plink_timer.data = (unsigned long) sta;
sta->plink_timer.function = mesh_plink_timer;
sta->plink_timeout = timeout;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 10ac6324c1d0..0cbcde11fae3 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1157,11 +1157,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
if (!conf) {
sdata_info(sdata,
"no channel context assigned to vif?, disconnecting\n");
- ieee80211_queue_work(&local->hw,
- &ifmgd->csa_connection_drop_work);
- mutex_unlock(&local->chanctx_mtx);
- mutex_unlock(&local->mtx);
- return;
+ goto drop_connection;
}
chanctx = container_of(conf, struct ieee80211_chanctx, conf);
@@ -1170,11 +1166,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
!(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
sdata_info(sdata,
"driver doesn't support chan-switch with channel contexts\n");
- ieee80211_queue_work(&local->hw,
- &ifmgd->csa_connection_drop_work);
- mutex_unlock(&local->chanctx_mtx);
- mutex_unlock(&local->mtx);
- return;
+ goto drop_connection;
}
ch_switch.timestamp = timestamp;
@@ -1186,11 +1178,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
if (drv_pre_channel_switch(sdata, &ch_switch)) {
sdata_info(sdata,
"preparing for channel switch failed, disconnecting\n");
- ieee80211_queue_work(&local->hw,
- &ifmgd->csa_connection_drop_work);
- mutex_unlock(&local->chanctx_mtx);
- mutex_unlock(&local->mtx);
- return;
+ goto drop_connection;
}
res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
@@ -1199,11 +1187,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
sdata_info(sdata,
"failed to reserve channel context for channel switch, disconnecting (err=%d)\n",
res);
- ieee80211_queue_work(&local->hw,
- &ifmgd->csa_connection_drop_work);
- mutex_unlock(&local->chanctx_mtx);
- mutex_unlock(&local->mtx);
- return;
+ goto drop_connection;
}
mutex_unlock(&local->chanctx_mtx);
@@ -1232,6 +1216,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
mod_timer(&ifmgd->chswitch_timer,
TU_TO_EXP_TIME((csa_ie.count - 1) *
cbss->beacon_interval));
+ return;
+ drop_connection:
+ ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work);
+ mutex_unlock(&local->chanctx_mtx);
+ mutex_unlock(&local->mtx);
}
static bool
@@ -1621,9 +1610,6 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
{
struct ieee80211_local *local = (void *) data;
- if (local->quiescing || local->suspended)
- return;
-
ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work);
}
@@ -2247,7 +2233,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
else
ssid_len = ssid[1];
- ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL,
+ ieee80211_send_probe_req(sdata, sdata->vif.addr, dst,
ssid + 2, ssid_len, NULL,
0, (u32) -1, true, 0,
ifmgd->associated->channel, false);
@@ -2359,6 +2345,24 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_ap_probereq_get);
+static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata,
+ const u8 *buf, size_t len, bool tx,
+ u16 reason)
+{
+ struct ieee80211_event event = {
+ .type = MLME_EVENT,
+ .u.mlme.data = tx ? DEAUTH_TX_EVENT : DEAUTH_RX_EVENT,
+ .u.mlme.reason = reason,
+ };
+
+ if (tx)
+ cfg80211_tx_mlme_mgmt(sdata->dev, buf, len);
+ else
+ cfg80211_rx_mlme_mgmt(sdata->dev, buf, len);
+
+ drv_event_callback(sdata->local, sdata, &event);
+}
+
static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
@@ -2384,8 +2388,9 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
}
mutex_unlock(&local->mtx);
- cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
- IEEE80211_DEAUTH_FRAME_LEN);
+ ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+
sdata_unlock(sdata);
}
@@ -2509,6 +2514,10 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
u8 bssid[ETH_ALEN];
u16 auth_alg, auth_transaction, status_code;
struct sta_info *sta;
+ struct ieee80211_event event = {
+ .type = MLME_EVENT,
+ .u.mlme.data = AUTH_EVENT,
+ };
sdata_assert_lock(sdata);
@@ -2541,6 +2550,9 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
mgmt->sa, status_code);
ieee80211_destroy_auth_data(sdata, false);
cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
+ event.u.mlme.status = MLME_DENIED;
+ event.u.mlme.reason = status_code;
+ drv_event_callback(sdata->local, sdata, &event);
return;
}
@@ -2563,6 +2575,8 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
return;
}
+ event.u.mlme.status = MLME_SUCCESS;
+ drv_event_callback(sdata->local, sdata, &event);
sdata_info(sdata, "authenticated\n");
ifmgd->auth_data->done = true;
ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
@@ -2681,7 +2695,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
- cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
+ ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code);
}
@@ -2707,7 +2721,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
- cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
+ ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code);
}
static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
@@ -2969,10 +2983,14 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
rate_control_rate_init(sta);
- if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
+ if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) {
set_sta_flag(sta, WLAN_STA_MFP);
+ sta->sta.mfp = true;
+ } else {
+ sta->sta.mfp = false;
+ }
- sta->sta.wme = elems.wmm_param;
+ sta->sta.wme = elems.wmm_param && local->hw.queues >= IEEE80211_NUM_ACS;
err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
@@ -3042,6 +3060,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
u8 *pos;
bool reassoc;
struct cfg80211_bss *bss;
+ struct ieee80211_event event = {
+ .type = MLME_EVENT,
+ .u.mlme.data = ASSOC_EVENT,
+ };
sdata_assert_lock(sdata);
@@ -3093,6 +3115,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
sdata_info(sdata, "%pM denied association (code=%d)\n",
mgmt->sa, status_code);
ieee80211_destroy_assoc_data(sdata, false);
+ event.u.mlme.status = MLME_DENIED;
+ event.u.mlme.reason = status_code;
+ drv_event_callback(sdata->local, sdata, &event);
} else {
if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) {
/* oops -- internal error -- send timeout for now */
@@ -3100,6 +3125,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
cfg80211_assoc_timeout(sdata->dev, bss);
return;
}
+ event.u.mlme.status = MLME_SUCCESS;
+ drv_event_callback(sdata->local, sdata, &event);
sdata_info(sdata, "associated\n");
/*
@@ -3301,6 +3328,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
int sig = ifmgd->ave_beacon_signal;
int last_sig = ifmgd->last_ave_beacon_signal;
+ struct ieee80211_event event = {
+ .type = RSSI_EVENT,
+ };
/*
* if signal crosses either of the boundaries, invoke callback
@@ -3309,12 +3339,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (sig > ifmgd->rssi_max_thold &&
(last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) {
ifmgd->last_ave_beacon_signal = sig;
- drv_rssi_callback(local, sdata, RSSI_EVENT_HIGH);
+ event.u.rssi.data = RSSI_EVENT_HIGH;
+ drv_event_callback(local, sdata, &event);
} else if (sig < ifmgd->rssi_min_thold &&
(last_sig >= ifmgd->rssi_max_thold ||
last_sig == 0)) {
ifmgd->last_ave_beacon_signal = sig;
- drv_rssi_callback(local, sdata, RSSI_EVENT_LOW);
+ event.u.rssi.data = RSSI_EVENT_LOW;
+ drv_event_callback(local, sdata, &event);
}
}
@@ -3419,6 +3451,26 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (ifmgd->csa_waiting_bcn)
ieee80211_chswitch_post_beacon(sdata);
+ /*
+ * Update beacon timing and dtim count on every beacon appearance. This
+ * will allow the driver to use the most updated values. Do it before
+ * comparing this one with last received beacon.
+ * IMPORTANT: These parameters would possibly be out of sync by the time
+ * the driver will use them. The synchronized view is currently
+ * guaranteed only in certain callbacks.
+ */
+ if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
+ sdata->vif.bss_conf.sync_tsf =
+ le64_to_cpu(mgmt->u.beacon.timestamp);
+ sdata->vif.bss_conf.sync_device_ts =
+ rx_status->device_timestamp;
+ if (elems.tim)
+ sdata->vif.bss_conf.sync_dtim_count =
+ elems.tim->dtim_count;
+ else
+ sdata->vif.bss_conf.sync_dtim_count = 0;
+ }
+
if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
return;
ifmgd->beacon_crc = ncrc;
@@ -3446,18 +3498,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
else
bss_conf->dtim_period = 1;
- if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
- sdata->vif.bss_conf.sync_tsf =
- le64_to_cpu(mgmt->u.beacon.timestamp);
- sdata->vif.bss_conf.sync_device_ts =
- rx_status->device_timestamp;
- if (elems.tim)
- sdata->vif.bss_conf.sync_dtim_count =
- elems.tim->dtim_count;
- else
- sdata->vif.bss_conf.sync_dtim_count = 0;
- }
-
changed |= BSS_CHANGED_BEACON_INFO;
ifmgd->have_beacon = true;
@@ -3488,8 +3528,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
WLAN_REASON_DEAUTH_LEAVING,
true, deauth_buf);
- cfg80211_tx_mlme_mgmt(sdata->dev, deauth_buf,
- sizeof(deauth_buf));
+ ieee80211_report_disconnect(sdata, deauth_buf,
+ sizeof(deauth_buf), true,
+ WLAN_REASON_DEAUTH_LEAVING);
return;
}
@@ -3607,8 +3648,8 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
tx, frame_buf);
- cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
- IEEE80211_DEAUTH_FRAME_LEN);
+ ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
+ reason);
}
static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
@@ -3802,12 +3843,18 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
ieee80211_destroy_auth_data(sdata, false);
} else if (ieee80211_probe_auth(sdata)) {
u8 bssid[ETH_ALEN];
+ struct ieee80211_event event = {
+ .type = MLME_EVENT,
+ .u.mlme.data = AUTH_EVENT,
+ .u.mlme.status = MLME_TIMEOUT,
+ };
memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN);
ieee80211_destroy_auth_data(sdata, false);
cfg80211_auth_timeout(sdata->dev, bssid);
+ drv_event_callback(sdata->local, sdata, &event);
}
} else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started)
run_again(sdata, ifmgd->auth_data->timeout);
@@ -3817,9 +3864,15 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) ||
ieee80211_do_assoc(sdata)) {
struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
+ struct ieee80211_event event = {
+ .type = MLME_EVENT,
+ .u.mlme.data = ASSOC_EVENT,
+ .u.mlme.status = MLME_TIMEOUT,
+ };
ieee80211_destroy_assoc_data(sdata, false);
cfg80211_assoc_timeout(sdata->dev, bss);
+ drv_event_callback(sdata->local, sdata, &event);
}
} else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
run_again(sdata, ifmgd->assoc_data->timeout);
@@ -3891,12 +3944,8 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data;
- struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- if (local->quiescing)
- return;
-
if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
return;
@@ -3912,9 +3961,6 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
- if (local->quiescing)
- return;
-
if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
return;
@@ -3977,6 +4023,34 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata)
IEEE80211_DEAUTH_FRAME_LEN);
}
+ /* This is a bit of a hack - we should find a better and more generic
+ * solution to this. Normally when suspending, cfg80211 will in fact
+ * deauthenticate. However, it doesn't (and cannot) stop an ongoing
+ * auth (not so important) or assoc (this is the problem) process.
+ *
+ * As a consequence, it can happen that we are in the process of both
+ * associating and suspending, and receive an association response
+ * after cfg80211 has checked if it needs to disconnect, but before
+ * we actually set the flag to drop incoming frames. This will then
+ * cause the workqueue flush to process the association response in
+ * the suspend, resulting in a successful association just before it
+ * tries to remove the interface from the driver, which now though
+ * has a channel context assigned ... this results in issues.
+ *
+ * To work around this (for now) simply deauth here again if we're
+ * now connected.
+ */
+ if (ifmgd->associated && !sdata->local->wowlan) {
+ u8 bssid[ETH_ALEN];
+ struct cfg80211_deauth_request req = {
+ .reason_code = WLAN_REASON_DEAUTH_LEAVING,
+ .bssid = bssid,
+ };
+
+ memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
+ ieee80211_mgd_deauth(sdata, &req);
+ }
+
sdata_unlock(sdata);
}
@@ -4365,6 +4439,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
} else
WARN_ON_ONCE(!ether_addr_equal(ifmgd->bssid, cbss->bssid));
+ /* Cancel scan to ensure that nothing interferes with connection */
+ if (local->scanning)
+ ieee80211_scan_cancel(local);
+
return 0;
}
@@ -4453,8 +4531,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
WLAN_REASON_UNSPECIFIED,
false, frame_buf);
- cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
- sizeof(frame_buf));
+ ieee80211_report_disconnect(sdata, frame_buf,
+ sizeof(frame_buf), true,
+ WLAN_REASON_UNSPECIFIED);
}
sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
@@ -4554,8 +4633,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
WLAN_REASON_UNSPECIFIED,
false, frame_buf);
- cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
- sizeof(frame_buf));
+ ieee80211_report_disconnect(sdata, frame_buf,
+ sizeof(frame_buf), true,
+ WLAN_REASON_UNSPECIFIED);
}
if (ifmgd->auth_data && !ifmgd->auth_data->done) {
@@ -4845,8 +4925,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
req->reason_code, tx,
frame_buf);
ieee80211_destroy_auth_data(sdata, false);
- cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
- IEEE80211_DEAUTH_FRAME_LEN);
+ ieee80211_report_disconnect(sdata, frame_buf,
+ sizeof(frame_buf), true,
+ req->reason_code);
return 0;
}
@@ -4860,8 +4941,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
req->reason_code, tx, frame_buf);
- cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
- IEEE80211_DEAUTH_FRAME_LEN);
+ ieee80211_report_disconnect(sdata, frame_buf,
+ sizeof(frame_buf), true,
+ req->reason_code);
return 0;
}
@@ -4893,8 +4975,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
req->reason_code, !req->local_state_change,
frame_buf);
- cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
- IEEE80211_DEAUTH_FRAME_LEN);
+ ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
+ req->reason_code);
return 0;
}
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index ca405b6b686d..ac6ad6238e3a 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -59,9 +59,26 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
cancel_work_sync(&local->dynamic_ps_enable_work);
del_timer_sync(&local->dynamic_ps_timer);
- local->wowlan = wowlan && local->open_count;
+ local->wowlan = wowlan;
if (local->wowlan) {
- int err = drv_suspend(local, wowlan);
+ int err;
+
+ /* Drivers don't expect to suspend while some operations like
+ * authenticating or associating are in progress. It doesn't
+ * make sense anyway to accept that, since the authentication
+ * or association would never finish since the driver can't do
+ * that on its own.
+ * Thus, clean up in-progress auth/assoc first.
+ */
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (!ieee80211_sdata_running(sdata))
+ continue;
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ continue;
+ ieee80211_mgd_quiesce(sdata);
+ }
+
+ err = drv_suspend(local, wowlan);
if (err < 0) {
local->quiescing = false;
local->wowlan = false;
@@ -80,6 +97,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
return err;
} else if (err > 0) {
WARN_ON(err != 1);
+ /* cfg80211 will call back into mac80211 to disconnect
+ * all interfaces, allow that to proceed properly
+ */
+ ieee80211_wake_queues_by_reason(hw,
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_SUSPEND,
+ false);
return err;
} else {
goto suspend;
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 80452cfd2dc5..60698fc7042e 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -17,10 +17,11 @@
#include "rc80211_minstrel.h"
#include "rc80211_minstrel_ht.h"
+#define AVG_AMPDU_SIZE 16
#define AVG_PKT_SIZE 1200
/* Number of bits for an average sized packet */
-#define MCS_NBITS (AVG_PKT_SIZE << 3)
+#define MCS_NBITS ((AVG_PKT_SIZE * AVG_AMPDU_SIZE) << 3)
/* Number of symbols for a packet with (bps) bits per symbol */
#define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps))
@@ -33,7 +34,8 @@
)
/* Transmit duration for the raw data part of an average sized packet */
-#define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
+#define MCS_DURATION(streams, sgi, bps) \
+ (MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) / AVG_AMPDU_SIZE)
#define BW_20 0
#define BW_40 1
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1101563357ea..9eab44317c87 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1912,8 +1912,7 @@ static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
/* Drop unencrypted frames if key is set. */
if (unlikely(!ieee80211_has_protected(fc) &&
!ieee80211_is_nullfunc(fc) &&
- ieee80211_is_data(fc) &&
- (rx->key || rx->sdata->drop_unencrypted)))
+ ieee80211_is_data(fc) && rx->key))
return -EACCES;
return 0;
@@ -2043,6 +2042,9 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
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;
@@ -2173,8 +2175,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
dev_kfree_skb(rx->skb);
continue;
}
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += rx->skb->len;
ieee80211_deliver_skb(rx);
}
@@ -2397,9 +2397,6 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
rx->skb->dev = dev;
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += rx->skb->len;
-
if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
!is_multicast_ether_addr(
((struct ethhdr *)rx->skb->data)->h_dest) &&
@@ -3125,6 +3122,12 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
goto rxh_next; \
} while (0);
+ /* Lock here to avoid hitting all of the data used in the RX
+ * path (e.g. key data, station data, ...) concurrently when
+ * a frame is released from the reorder buffer due to timeout
+ * from the timer, potentially concurrently with RX from the
+ * driver.
+ */
spin_lock_bh(&rx->local->rx_path_lock);
while ((skb = __skb_dequeue(frames))) {
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 05f0d711b6d8..7bb6a9383f58 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -928,11 +928,12 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
const u8 *ssid, u8 ssid_len,
- struct ieee80211_channel *chan,
+ struct ieee80211_channel **channels,
+ unsigned int n_channels,
enum nl80211_bss_scan_width scan_width)
{
struct ieee80211_local *local = sdata->local;
- int ret = -EBUSY;
+ int ret = -EBUSY, i, n_ch = 0;
enum ieee80211_band band;
mutex_lock(&local->mtx);
@@ -942,9 +943,8 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
goto unlock;
/* fill internal scan request */
- if (!chan) {
- int i, max_n;
- int n_ch = 0;
+ if (!channels) {
+ int max_n;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!local->hw.wiphy->bands[band])
@@ -969,12 +969,19 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
local->int_scan_req->n_channels = n_ch;
} else {
- if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR |
- IEEE80211_CHAN_DISABLED)))
+ for (i = 0; i < n_channels; i++) {
+ if (channels[i]->flags & (IEEE80211_CHAN_NO_IR |
+ IEEE80211_CHAN_DISABLED))
+ continue;
+
+ local->int_scan_req->channels[n_ch] = channels[i];
+ n_ch++;
+ }
+
+ if (WARN_ON_ONCE(n_ch == 0))
goto unlock;
- local->int_scan_req->channels[0] = chan;
- local->int_scan_req->n_channels = 1;
+ local->int_scan_req->n_channels = n_ch;
}
local->int_scan_req->ssids = &local->scan_ssid;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 00ca8dcc2bcf..aacaa1a85e63 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -229,17 +229,9 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
*/
void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
{
- int i;
-
if (sta->rate_ctrl)
rate_control_free_sta(sta);
- if (sta->tx_lat) {
- for (i = 0; i < IEEE80211_NUM_TIDS; i++)
- kfree(sta->tx_lat[i].bins);
- kfree(sta->tx_lat);
- }
-
sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
kfree(rcu_dereference_raw(sta->sta.rates));
@@ -295,42 +287,12 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
struct timespec uptime;
- struct ieee80211_tx_latency_bin_ranges *tx_latency;
int i;
sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
if (!sta)
return NULL;
- rcu_read_lock();
- tx_latency = rcu_dereference(local->tx_latency);
- /* init stations Tx latency statistics && TID bins */
- if (tx_latency) {
- sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS *
- sizeof(struct ieee80211_tx_latency_stat),
- GFP_ATOMIC);
- if (!sta->tx_lat) {
- rcu_read_unlock();
- goto free;
- }
-
- if (tx_latency->n_ranges) {
- for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
- /* size of bins is size of the ranges +1 */
- sta->tx_lat[i].bin_count =
- tx_latency->n_ranges + 1;
- sta->tx_lat[i].bins =
- kcalloc(sta->tx_lat[i].bin_count,
- sizeof(u32), GFP_ATOMIC);
- if (!sta->tx_lat[i].bins) {
- rcu_read_unlock();
- goto free;
- }
- }
- }
- }
- rcu_read_unlock();
-
spin_lock_init(&sta->lock);
spin_lock_init(&sta->ps_lock);
INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
@@ -359,8 +321,10 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++)
ewma_init(&sta->chain_signal_avg[i], 1024, 8);
- if (sta_prepare_rate_control(local, sta, gfp))
- goto free;
+ if (sta_prepare_rate_control(local, sta, gfp)) {
+ kfree(sta);
+ return NULL;
+ }
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
/*
@@ -405,16 +369,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
}
sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
- return sta;
-free:
- if (sta->tx_lat) {
- for (i = 0; i < IEEE80211_NUM_TIDS; i++)
- kfree(sta->tx_lat[i].bins);
- kfree(sta->tx_lat);
- }
- kfree(sta);
- return NULL;
+ return sta;
}
static int sta_info_insert_check(struct sta_info *sta)
@@ -1275,7 +1231,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
}
info->band = chanctx_conf->def.chan->band;
- ieee80211_xmit(sdata, skb);
+ ieee80211_xmit(sdata, sta, skb);
rcu_read_unlock();
}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 925e68fe64c7..248f56e59ebc 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -234,25 +234,6 @@ struct sta_ampdu_mlme {
u8 dialog_token_allocator;
};
-/*
- * struct ieee80211_tx_latency_stat - Tx latency statistics
- *
- * Measures TX latency and jitter for a station per TID.
- *
- * @max: worst case latency
- * @sum: sum of all latencies
- * @counter: amount of Tx frames sent from interface
- * @bins: each bin counts how many frames transmitted within a certain
- * latency range. when disabled it is NULL.
- * @bin_count: amount of bins.
- */
-struct ieee80211_tx_latency_stat {
- u32 max;
- u32 sum;
- u32 counter;
- u32 *bins;
- u32 bin_count;
-};
/* Value to indicate no TID reservation */
#define IEEE80211_TID_UNRESERVED 0xff
@@ -314,7 +295,6 @@ struct ieee80211_tx_latency_stat {
* @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
- * @tx_lat: Tx latency statistics
* @llid: Local link ID
* @plid: Peer link ID
* @reason: Cancel reason on PLINK_HOLDING state
@@ -435,8 +415,6 @@ struct sta_info {
struct sta_ampdu_mlme ampdu_mlme;
u8 timer_to_tid[IEEE80211_NUM_TIDS];
- struct ieee80211_tx_latency_stat *tx_lat;
-
#ifdef CONFIG_MAC80211_MESH
/*
* Mesh peer link attributes
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index e679b7c9b160..2c51742428d5 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -12,7 +12,6 @@
#include <linux/export.h>
#include <linux/etherdevice.h>
-#include <linux/time.h>
#include <net/mac80211.h>
#include <asm/unaligned.h>
#include "ieee80211_i.h"
@@ -515,73 +514,6 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
}
/*
- * Measure Tx frame completion and removal time for Tx latency statistics
- * calculation. A single Tx frame latency should be measured from when it
- * is entering the Kernel until we receive Tx complete confirmation indication
- * and remove the skb.
- */
-static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,
- struct sk_buff *skb,
- struct sta_info *sta,
- struct ieee80211_hdr *hdr)
-{
- u32 msrmnt;
- u16 tid;
- u8 *qc;
- int i, bin_range_count;
- u32 *bin_ranges;
- __le16 fc;
- struct ieee80211_tx_latency_stat *tx_lat;
- struct ieee80211_tx_latency_bin_ranges *tx_latency;
- ktime_t skb_arv = skb->tstamp;
-
- tx_latency = rcu_dereference(local->tx_latency);
-
- /* assert Tx latency stats are enabled & frame arrived when enabled */
- if (!tx_latency || !ktime_to_ns(skb_arv))
- return;
-
- fc = hdr->frame_control;
-
- if (!ieee80211_is_data(fc)) /* make sure it is a data frame */
- return;
-
- /* get frame tid */
- if (ieee80211_is_data_qos(hdr->frame_control)) {
- qc = ieee80211_get_qos_ctl(hdr);
- tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
- } else {
- tid = 0;
- }
-
- tx_lat = &sta->tx_lat[tid];
-
- /* Calculate the latency */
- msrmnt = ktime_to_ms(ktime_sub(ktime_get(), skb_arv));
-
- if (tx_lat->max < msrmnt) /* update stats */
- tx_lat->max = msrmnt;
- tx_lat->counter++;
- tx_lat->sum += msrmnt;
-
- if (!tx_lat->bins) /* bins not activated */
- return;
-
- /* count how many Tx frames transmitted with the appropriate latency */
- bin_range_count = tx_latency->n_ranges;
- bin_ranges = tx_latency->ranges;
-
- for (i = 0; i < bin_range_count; i++) {
- if (msrmnt <= bin_ranges[i]) {
- tx_lat->bins[i]++;
- break;
- }
- }
- if (i == bin_range_count) /* msrmnt is bigger than the biggest range */
- tx_lat->bins[i]++;
-}
-
-/*
* Use a static threshold for now, best value to be determined
* by testing ...
* Should it depend on:
@@ -853,12 +785,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
if (acked)
sta->last_ack_signal = info->status.ack_signal;
-
- /*
- * Measure frame removal for tx latency
- * statistics calculation
- */
- ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr);
}
rcu_read_unlock();
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index c9f9752217ac..fff0d864adfa 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -136,6 +136,24 @@ ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata,
*pos = 2 * subband_cnt;
}
+static void ieee80211_tdls_add_oper_classes(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
+{
+ u8 *pos;
+ u8 op_class;
+
+ if (!ieee80211_chandef_to_operating_class(&sdata->vif.bss_conf.chandef,
+ &op_class))
+ return;
+
+ pos = skb_put(skb, 4);
+ *pos++ = WLAN_EID_SUPPORTED_REGULATORY_CLASSES;
+ *pos++ = 2; /* len */
+
+ *pos++ = op_class;
+ *pos++ = op_class; /* give current operating class as alternate too */
+}
+
static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb)
{
u8 *pos = (void *)skb_put(skb, 3);
@@ -193,6 +211,17 @@ static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata,
memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN);
}
+static void
+ieee80211_tdls_add_aid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
+{
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ u8 *pos = (void *)skb_put(skb, 4);
+
+ *pos++ = WLAN_EID_AID;
+ *pos++ = 2; /* len */
+ put_unaligned_le16(ifmgd->aid, pos);
+}
+
/* translate numbering in the WMM parameter IE to the mac80211 notation */
static enum ieee80211_ac_numbers ieee80211_ac_from_wmm(int ac)
{
@@ -271,21 +300,11 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
struct ieee80211_sta_ht_cap ht_cap;
+ struct ieee80211_sta_vht_cap vht_cap;
struct sta_info *sta = NULL;
size_t offset = 0, noffset;
u8 *pos;
- rcu_read_lock();
-
- /* we should have the peer STA if we're already responding */
- if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
- sta = sta_info_get(sdata, peer);
- if (WARN_ON_ONCE(!sta)) {
- rcu_read_unlock();
- return;
- }
- }
-
ieee80211_add_srates_ie(sdata, skb, false, band);
ieee80211_add_ext_srates_ie(sdata, skb, false, band);
ieee80211_tdls_add_supp_channels(sdata, skb);
@@ -338,6 +357,19 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
offset = noffset;
}
+ rcu_read_lock();
+
+ /* we should have the peer STA if we're already responding */
+ if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
+ sta = sta_info_get(sdata, peer);
+ if (WARN_ON_ONCE(!sta)) {
+ rcu_read_unlock();
+ return;
+ }
+ }
+
+ ieee80211_tdls_add_oper_classes(sdata, skb);
+
/*
* with TDLS we can switch channels, and HT-caps are not necessarily
* the same on all bands. The specification limits the setup to a
@@ -346,7 +378,9 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
sband = local->hw.wiphy->bands[band];
memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
- if (action_code == WLAN_TDLS_SETUP_REQUEST && ht_cap.ht_supported) {
+ if ((action_code == WLAN_TDLS_SETUP_REQUEST ||
+ action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) &&
+ ht_cap.ht_supported) {
ieee80211_apply_htcap_overrides(sdata, &ht_cap);
/* disable SMPS in TDLS initiator */
@@ -368,12 +402,63 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap);
}
- rcu_read_unlock();
-
if (ht_cap.ht_supported &&
(ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
ieee80211_tdls_add_bss_coex_ie(skb);
+ ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
+
+ /* add any custom IEs that go before VHT capabilities */
+ if (extra_ies_len) {
+ static const u8 before_vht_cap[] = {
+ WLAN_EID_SUPP_RATES,
+ WLAN_EID_COUNTRY,
+ WLAN_EID_EXT_SUPP_RATES,
+ WLAN_EID_SUPPORTED_CHANNELS,
+ WLAN_EID_RSN,
+ WLAN_EID_EXT_CAPABILITY,
+ WLAN_EID_QOS_CAPA,
+ WLAN_EID_FAST_BSS_TRANSITION,
+ WLAN_EID_TIMEOUT_INTERVAL,
+ WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+ WLAN_EID_MULTI_BAND,
+ };
+ noffset = ieee80211_ie_split(extra_ies, extra_ies_len,
+ before_vht_cap,
+ ARRAY_SIZE(before_vht_cap),
+ offset);
+ pos = skb_put(skb, noffset - offset);
+ memcpy(pos, extra_ies + offset, noffset - offset);
+ offset = noffset;
+ }
+
+ /* build the VHT-cap similarly to the HT-cap */
+ memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
+ if ((action_code == WLAN_TDLS_SETUP_REQUEST ||
+ action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) &&
+ vht_cap.vht_supported) {
+ ieee80211_apply_vhtcap_overrides(sdata, &vht_cap);
+
+ /* the AID is present only when VHT is implemented */
+ if (action_code == WLAN_TDLS_SETUP_REQUEST)
+ ieee80211_tdls_add_aid(sdata, skb);
+
+ pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
+ ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap);
+ } else if (action_code == WLAN_TDLS_SETUP_RESPONSE &&
+ vht_cap.vht_supported && sta->sta.vht_cap.vht_supported) {
+ /* the peer caps are already intersected with our own */
+ memcpy(&vht_cap, &sta->sta.vht_cap, sizeof(vht_cap));
+
+ /* the AID is present only when VHT is implemented */
+ ieee80211_tdls_add_aid(sdata, skb);
+
+ pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
+ ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap);
+ }
+
+ rcu_read_unlock();
+
/* add any remaining IEs */
if (extra_ies_len) {
noffset = extra_ies_len;
@@ -381,7 +466,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
memcpy(pos, extra_ies + offset, noffset - offset);
}
- ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
}
static void
@@ -394,6 +478,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
size_t offset = 0, noffset;
struct sta_info *sta, *ap_sta;
+ enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
u8 *pos;
rcu_read_lock();
@@ -453,6 +538,21 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
}
}
+ ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
+
+ /* only include VHT-operation if not on the 2.4GHz band */
+ if (band != IEEE80211_BAND_2GHZ && !ap_sta->sta.vht_cap.vht_supported &&
+ sta->sta.vht_cap.vht_supported) {
+ struct ieee80211_chanctx_conf *chanctx_conf =
+ rcu_dereference(sdata->vif.chanctx_conf);
+ if (!WARN_ON(!chanctx_conf)) {
+ pos = skb_put(skb, 2 +
+ sizeof(struct ieee80211_vht_operation));
+ ieee80211_ie_build_vht_oper(pos, &sta->sta.vht_cap,
+ &chanctx_conf->def);
+ }
+ }
+
rcu_read_unlock();
/* add any remaining IEs */
@@ -461,8 +561,6 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
pos = skb_put(skb, noffset - offset);
memcpy(pos, extra_ies + offset, noffset - offset);
}
-
- ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
}
static void
@@ -708,8 +806,12 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata,
26 + /* max(WMM-info, WMM-param) */
2 + max(sizeof(struct ieee80211_ht_cap),
sizeof(struct ieee80211_ht_operation)) +
+ 2 + max(sizeof(struct ieee80211_vht_cap),
+ sizeof(struct ieee80211_vht_operation)) +
50 + /* supported channels */
3 + /* 40/20 BSS coex */
+ 4 + /* AID */
+ 4 + /* oper classes */
extra_ies_len +
sizeof(struct ieee80211_tdls_lnkie));
if (!skb)
@@ -907,7 +1009,7 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer) &&
!ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) {
ret = -EBUSY;
- goto exit;
+ goto out_unlock;
}
/*
@@ -922,27 +1024,34 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
if (!sta_info_get(sdata, peer)) {
rcu_read_unlock();
ret = -ENOLINK;
- goto exit;
+ goto out_unlock;
}
rcu_read_unlock();
}
ieee80211_flush_queues(local, sdata, false);
+ memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN);
+ mutex_unlock(&local->mtx);
+ /* we cannot take the mutex while preparing the setup packet */
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
dialog_token, status_code,
peer_capability, initiator,
extra_ies, extra_ies_len, 0,
NULL);
- if (ret < 0)
- goto exit;
+ if (ret < 0) {
+ mutex_lock(&local->mtx);
+ eth_zero_addr(sdata->u.mgd.tdls_peer);
+ mutex_unlock(&local->mtx);
+ return ret;
+ }
- memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN);
ieee80211_queue_delayed_work(&sdata->local->hw,
&sdata->u.mgd.tdls_peer_del_work,
TDLS_PEER_SETUP_TIMEOUT);
+ return 0;
-exit:
+out_unlock:
mutex_unlock(&local->mtx);
return ret;
}
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 263a9561eb26..e9e462b349e5 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1256,28 +1256,28 @@ TRACE_EVENT(drv_set_rekey_data,
LOCAL_PR_ARG, VIF_PR_ARG)
);
-TRACE_EVENT(drv_rssi_callback,
+TRACE_EVENT(drv_event_callback,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- enum ieee80211_rssi_event rssi_event),
+ const struct ieee80211_event *_event),
- TP_ARGS(local, sdata, rssi_event),
+ TP_ARGS(local, sdata, _event),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
- __field(u32, rssi_event)
+ __field(u32, type)
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
- __entry->rssi_event = rssi_event;
+ __entry->type = _event->type;
),
TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT " rssi_event:%d",
- LOCAL_PR_ARG, VIF_PR_ARG, __entry->rssi_event
+ LOCAL_PR_FMT VIF_PR_FMT " event:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->type
)
);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 88a18ffe2975..e5d679f38cc1 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -20,7 +20,6 @@
#include <linux/bitmap.h>
#include <linux/rcupdate.h>
#include <linux/export.h>
-#include <linux/time.h>
#include <net/net_namespace.h>
#include <net/ieee80211_radiotap.h>
#include <net/cfg80211.h>
@@ -594,23 +593,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
else if (!is_multicast_ether_addr(hdr->addr1) &&
(key = rcu_dereference(tx->sdata->default_unicast_key)))
tx->key = key;
- else if (info->flags & IEEE80211_TX_CTL_INJECTED)
- tx->key = NULL;
- else if (!tx->sdata->drop_unencrypted)
- tx->key = NULL;
- else if (tx->skb->protocol == tx->sdata->control_port_protocol)
- tx->key = NULL;
- else if (ieee80211_is_robust_mgmt_frame(tx->skb) &&
- !(ieee80211_is_action(hdr->frame_control) &&
- tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))
- tx->key = NULL;
- else if (ieee80211_is_mgmt(hdr->frame_control) &&
- !ieee80211_is_robust_mgmt_frame(tx->skb))
+ else
tx->key = NULL;
- else {
- I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
- return TX_DROP;
- }
if (tx->key) {
bool skip_hw = false;
@@ -1136,11 +1120,13 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
/*
* initialises @tx
+ * pass %NULL for the station if unknown, a valid pointer if known
+ * or an ERR_PTR() if the station is known not to exist
*/
static ieee80211_tx_result
ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
struct ieee80211_tx_data *tx,
- struct sk_buff *skb)
+ struct sta_info *sta, struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_hdr *hdr;
@@ -1163,17 +1149,22 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
hdr = (struct ieee80211_hdr *) skb->data;
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
- tx->sta = rcu_dereference(sdata->u.vlan.sta);
- if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
- return TX_DROP;
- } else if (info->flags & (IEEE80211_TX_CTL_INJECTED |
- IEEE80211_TX_INTFL_NL80211_FRAME_TX) ||
- tx->sdata->control_port_protocol == tx->skb->protocol) {
- tx->sta = sta_info_get_bss(sdata, hdr->addr1);
+ if (likely(sta)) {
+ if (!IS_ERR(sta))
+ tx->sta = sta;
+ } else {
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+ tx->sta = rcu_dereference(sdata->u.vlan.sta);
+ if (!tx->sta && sdata->wdev.use_4addr)
+ return TX_DROP;
+ } else if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+ IEEE80211_TX_CTL_INJECTED) ||
+ tx->sdata->control_port_protocol == tx->skb->protocol) {
+ tx->sta = sta_info_get_bss(sdata, hdr->addr1);
+ }
+ if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
+ tx->sta = sta_info_get(sdata, hdr->addr1);
}
- if (!tx->sta)
- tx->sta = sta_info_get(sdata, hdr->addr1);
if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
!ieee80211_is_qos_nullfunc(hdr->frame_control) &&
@@ -1421,8 +1412,9 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_data tx;
+ struct sk_buff *skb2;
- if (ieee80211_tx_prepare(sdata, &tx, skb) == TX_DROP)
+ if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP)
return false;
info->band = band;
@@ -1439,6 +1431,14 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
*sta = NULL;
}
+ /* this function isn't suitable for fragmented data frames */
+ skb2 = __skb_dequeue(&tx.skbs);
+ if (WARN_ON(skb2 != skb || !skb_queue_empty(&tx.skbs))) {
+ ieee80211_free_txskb(hw, skb2);
+ ieee80211_purge_tx_queue(hw, &tx.skbs);
+ return false;
+ }
+
return true;
}
EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
@@ -1447,7 +1447,8 @@ EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
* Returns false if the frame couldn't be transmitted but was queued instead.
*/
static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, bool txpending)
+ struct sta_info *sta, struct sk_buff *skb,
+ bool txpending)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_data tx;
@@ -1463,7 +1464,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
/* initialises tx */
led_len = skb->len;
- res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
+ res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb);
if (unlikely(res_prepare == TX_DROP)) {
ieee80211_free_txskb(&local->hw, skb);
@@ -1519,7 +1520,8 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
return 0;
}
-void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
+void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta, struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1554,7 +1556,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
}
ieee80211_set_qos_hdr(sdata, skb);
- ieee80211_tx(sdata, skb, false);
+ ieee80211_tx(sdata, sta, skb, false);
}
static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
@@ -1775,7 +1777,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
goto fail_rcu;
info->band = chandef->chan->band;
- ieee80211_xmit(sdata, skb);
+ ieee80211_xmit(sdata, NULL, skb);
rcu_read_unlock();
return NETDEV_TX_OK;
@@ -1787,21 +1789,89 @@ fail:
return NETDEV_TX_OK; /* meaning, we dealt with the skb */
}
-/*
- * Measure Tx frame arrival time for Tx latency statistics calculation
- * A single Tx frame latency should be measured from when it is entering the
- * Kernel until we receive Tx complete confirmation indication and the skb is
- * freed.
- */
-static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local,
- struct sk_buff *skb)
+static inline bool ieee80211_is_tdls_setup(struct sk_buff *skb)
{
- struct ieee80211_tx_latency_bin_ranges *tx_latency;
+ u16 ethertype = (skb->data[12] << 8) | skb->data[13];
- tx_latency = rcu_dereference(local->tx_latency);
- if (!tx_latency)
- return;
- skb->tstamp = ktime_get();
+ return ethertype == ETH_P_TDLS &&
+ skb->len > 14 &&
+ skb->data[14] == WLAN_TDLS_SNAP_RFTYPE;
+}
+
+static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb,
+ struct sta_info **sta_out)
+{
+ struct sta_info *sta;
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP_VLAN:
+ sta = rcu_dereference(sdata->u.vlan.sta);
+ if (sta) {
+ *sta_out = sta;
+ return 0;
+ } else if (sdata->wdev.use_4addr) {
+ return -ENOLINK;
+ }
+ /* fall through */
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_OCB:
+ case NL80211_IFTYPE_ADHOC:
+ if (is_multicast_ether_addr(skb->data)) {
+ *sta_out = ERR_PTR(-ENOENT);
+ return 0;
+ }
+ sta = sta_info_get_bss(sdata, skb->data);
+ break;
+ case NL80211_IFTYPE_WDS:
+ sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
+ break;
+#ifdef CONFIG_MAC80211_MESH
+ case NL80211_IFTYPE_MESH_POINT:
+ /* determined much later */
+ *sta_out = NULL;
+ return 0;
+#endif
+ case NL80211_IFTYPE_STATION:
+ if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
+ sta = sta_info_get(sdata, skb->data);
+ if (sta) {
+ bool tdls_peer, tdls_auth;
+
+ tdls_peer = test_sta_flag(sta,
+ WLAN_STA_TDLS_PEER);
+ tdls_auth = test_sta_flag(sta,
+ WLAN_STA_TDLS_PEER_AUTH);
+
+ if (tdls_peer && tdls_auth) {
+ *sta_out = sta;
+ return 0;
+ }
+
+ /*
+ * TDLS link during setup - throw out frames to
+ * peer. Allow TDLS-setup frames to unauthorized
+ * peers for the special case of a link teardown
+ * after a TDLS sta is removed due to being
+ * unreachable.
+ */
+ if (tdls_peer && !tdls_auth &&
+ !ieee80211_is_tdls_setup(skb))
+ return -EINVAL;
+ }
+
+ }
+
+ sta = sta_info_get(sdata, sdata->u.mgd.bssid);
+ if (!sta)
+ return -ENOLINK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *sta_out = sta ?: ERR_PTR(-ENOENT);
+ return 0;
}
/**
@@ -1823,7 +1893,8 @@ static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local,
* Returns: the (possibly reallocated) skb or an ERR_PTR() code
*/
static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, u32 info_flags)
+ struct sk_buff *skb, u32 info_flags,
+ struct sta_info *sta)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info;
@@ -1836,9 +1907,8 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
const u8 *encaps_data;
int encaps_len, skip_header_bytes;
int nh_pos, h_pos;
- struct sta_info *sta = NULL;
- bool wme_sta = false, authorized = false, tdls_auth = false;
- bool tdls_peer = false, tdls_setup_frame = false;
+ bool wme_sta = false, authorized = false;
+ bool tdls_peer;
bool multicast;
u16 info_id = 0;
struct ieee80211_chanctx_conf *chanctx_conf;
@@ -1846,6 +1916,9 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
enum ieee80211_band band;
int ret;
+ if (IS_ERR(sta))
+ sta = NULL;
+
/* convert Ethernet header to proper 802.11 header (based on
* operation mode) */
ethertype = (skb->data[12] << 8) | skb->data[13];
@@ -1853,8 +1926,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
- sta = rcu_dereference(sdata->u.vlan.sta);
- if (sta) {
+ 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);
@@ -1873,7 +1945,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
goto free;
}
band = chanctx_conf->def.chan->band;
- if (sta)
+ if (sdata->wdev.use_4addr)
break;
/* fall through */
case NL80211_IFTYPE_AP:
@@ -1977,38 +2049,10 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
break;
#endif
case NL80211_IFTYPE_STATION:
- if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
- sta = sta_info_get(sdata, skb->data);
- if (sta) {
- authorized = test_sta_flag(sta,
- WLAN_STA_AUTHORIZED);
- wme_sta = sta->sta.wme;
- tdls_peer = test_sta_flag(sta,
- WLAN_STA_TDLS_PEER);
- tdls_auth = test_sta_flag(sta,
- WLAN_STA_TDLS_PEER_AUTH);
- }
-
- if (tdls_peer)
- tdls_setup_frame =
- ethertype == ETH_P_TDLS &&
- skb->len > 14 &&
- skb->data[14] == WLAN_TDLS_SNAP_RFTYPE;
- }
+ /* we already did checks when looking up the RA STA */
+ tdls_peer = test_sta_flag(sta, WLAN_STA_TDLS_PEER);
- /*
- * TDLS link during setup - throw out frames to peer. We allow
- * TDLS-setup frames to unauthorized peers for the special case
- * of a link teardown after a TDLS sta is removed due to being
- * unreachable.
- */
- if (tdls_peer && !tdls_auth && !tdls_setup_frame) {
- ret = -EINVAL;
- goto free;
- }
-
- /* send direct packets to authorized TDLS peers */
- if (tdls_peer && tdls_auth) {
+ if (tdls_peer) {
/* DA SA BSSID */
memcpy(hdr.addr1, skb->data, ETH_ALEN);
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
@@ -2070,26 +2114,19 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
goto free;
}
- /*
- * There's no need to try to look up the destination
- * if it is a multicast address (which can only happen
- * in AP mode)
- */
multicast = is_multicast_ether_addr(hdr.addr1);
- if (!multicast) {
- sta = sta_info_get(sdata, hdr.addr1);
- if (sta) {
- authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
- wme_sta = sta->sta.wme;
- }
- }
- /* For mesh, the use of the QoS header is mandatory */
- if (ieee80211_vif_is_mesh(&sdata->vif))
+ /* sta is always NULL for mesh */
+ if (sta) {
+ authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
+ wme_sta = sta->sta.wme;
+ } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ /* For mesh, the use of the QoS header is mandatory */
wme_sta = true;
+ }
- /* receiver and we are QoS enabled, use a QoS type frame */
- if (wme_sta && local->hw.queues >= IEEE80211_NUM_ACS) {
+ /* receiver does QoS (which also means we do) use it */
+ if (wme_sta) {
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
hdrlen += 2;
}
@@ -2259,7 +2296,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
u32 info_flags)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
if (unlikely(skb->len < ETH_HLEN)) {
kfree_skb(skb);
@@ -2268,10 +2305,12 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
rcu_read_lock();
- /* Measure frame arrival for Tx latency statistics calculation */
- ieee80211_tx_latency_start_msrmnt(local, skb);
+ if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
+ kfree_skb(skb);
+ goto out;
+ }
- skb = ieee80211_build_hdr(sdata, skb, info_flags);
+ skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
if (IS_ERR(skb))
goto out;
@@ -2279,7 +2318,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
dev->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
- ieee80211_xmit(sdata, skb);
+ ieee80211_xmit(sdata, sta, skb);
out:
rcu_read_unlock();
}
@@ -2307,10 +2346,17 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
.local = sdata->local,
.sdata = sdata,
};
+ struct sta_info *sta;
rcu_read_lock();
- skb = ieee80211_build_hdr(sdata, skb, info_flags);
+ if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
+ kfree_skb(skb);
+ skb = ERR_PTR(-EINVAL);
+ goto out;
+ }
+
+ skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
if (IS_ERR(skb))
goto out;
@@ -2368,7 +2414,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
return true;
}
info->band = chanctx_conf->def.chan->band;
- result = ieee80211_tx(sdata, skb, true);
+ result = ieee80211_tx(sdata, NULL, skb, true);
} else {
struct sk_buff_head skbs;
@@ -3106,7 +3152,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
if (sdata->vif.type == NL80211_IFTYPE_AP)
sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
- if (!ieee80211_tx_prepare(sdata, &tx, skb))
+ if (!ieee80211_tx_prepare(sdata, &tx, NULL, skb))
break;
dev_kfree_skb_any(skb);
}
@@ -3238,6 +3284,6 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
*/
local_bh_disable();
IEEE80211_SKB_CB(skb)->band = band;
- ieee80211_xmit(sdata, skb);
+ ieee80211_xmit(sdata, NULL, skb);
local_bh_enable();
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 8428f4a95479..256647cb1d24 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -625,13 +625,14 @@ void ieee80211_wake_vif_queues(struct ieee80211_local *local,
reason, true);
}
-static void __iterate_active_interfaces(struct ieee80211_local *local,
- u32 iter_flags,
- void (*iterator)(void *data, u8 *mac,
- struct ieee80211_vif *vif),
- void *data)
+static void __iterate_interfaces(struct ieee80211_local *local,
+ u32 iter_flags,
+ void (*iterator)(void *data, u8 *mac,
+ struct ieee80211_vif *vif),
+ void *data)
{
struct ieee80211_sub_if_data *sdata;
+ bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
switch (sdata->vif.type) {
@@ -645,9 +646,9 @@ static void __iterate_active_interfaces(struct ieee80211_local *local,
break;
}
if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
- !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+ active_only && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
continue;
- if (ieee80211_sdata_running(sdata))
+ if (ieee80211_sdata_running(sdata) || !active_only)
iterator(data, sdata->vif.addr,
&sdata->vif);
}
@@ -656,12 +657,12 @@ static void __iterate_active_interfaces(struct ieee80211_local *local,
lockdep_is_held(&local->iflist_mtx) ||
lockdep_rtnl_is_held());
if (sdata &&
- (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
+ (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
sdata->flags & IEEE80211_SDATA_IN_DRIVER))
iterator(data, sdata->vif.addr, &sdata->vif);
}
-void ieee80211_iterate_active_interfaces(
+void ieee80211_iterate_interfaces(
struct ieee80211_hw *hw, u32 iter_flags,
void (*iterator)(void *data, u8 *mac,
struct ieee80211_vif *vif),
@@ -670,10 +671,10 @@ void ieee80211_iterate_active_interfaces(
struct ieee80211_local *local = hw_to_local(hw);
mutex_lock(&local->iflist_mtx);
- __iterate_active_interfaces(local, iter_flags, iterator, data);
+ __iterate_interfaces(local, iter_flags, iterator, data);
mutex_unlock(&local->iflist_mtx);
}
-EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
+EXPORT_SYMBOL_GPL(ieee80211_iterate_interfaces);
void ieee80211_iterate_active_interfaces_atomic(
struct ieee80211_hw *hw, u32 iter_flags,
@@ -684,7 +685,8 @@ void ieee80211_iterate_active_interfaces_atomic(
struct ieee80211_local *local = hw_to_local(hw);
rcu_read_lock();
- __iterate_active_interfaces(local, iter_flags, iterator, data);
+ __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
+ iterator, data);
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
@@ -699,7 +701,8 @@ void ieee80211_iterate_active_interfaces_rtnl(
ASSERT_RTNL();
- __iterate_active_interfaces(local, iter_flags, iterator, data);
+ __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
+ iterator, data);
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
@@ -742,6 +745,18 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
}
EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif);
+struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+ if (!ieee80211_sdata_running(sdata) ||
+ !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+ return NULL;
+
+ return &sdata->wdev;
+}
+EXPORT_SYMBOL_GPL(ieee80211_vif_to_wdev);
+
/*
* Nothing should have been stuffed into the workqueue during
* the suspend->resume cycle. Since we can't check each caller
@@ -1811,8 +1826,25 @@ int ieee80211_reconfig(struct ieee80211_local *local)
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_MONITOR &&
- ieee80211_sdata_running(sdata))
+ ieee80211_sdata_running(sdata)) {
res = drv_add_interface(local, sdata);
+ if (WARN_ON(res))
+ break;
+ }
+ }
+
+ /* If adding any of the interfaces failed above, roll back and
+ * report failure.
+ */
+ if (res) {
+ list_for_each_entry_continue_reverse(sdata, &local->interfaces,
+ list)
+ if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+ ieee80211_sdata_running(sdata))
+ drv_remove_interface(local, sdata);
+ ieee80211_handle_reconfig_failure(local);
+ return res;
}
/* add channel contexts */
@@ -2344,6 +2376,41 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
return pos + sizeof(struct ieee80211_ht_operation);
}
+u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
+ const struct cfg80211_chan_def *chandef)
+{
+ struct ieee80211_vht_operation *vht_oper;
+
+ *pos++ = WLAN_EID_VHT_OPERATION;
+ *pos++ = sizeof(struct ieee80211_vht_operation);
+ vht_oper = (struct ieee80211_vht_operation *)pos;
+ vht_oper->center_freq_seg1_idx = ieee80211_frequency_to_channel(
+ chandef->center_freq1);
+ if (chandef->center_freq2)
+ vht_oper->center_freq_seg2_idx =
+ ieee80211_frequency_to_channel(chandef->center_freq2);
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_160:
+ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
+ break;
+ default:
+ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+
+ /* don't require special VHT peer rates */
+ vht_oper->basic_mcs_set = cpu_to_le16(0xffff);
+
+ return pos + sizeof(struct ieee80211_vht_operation);
+}
+
void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
const struct ieee80211_ht_operation *ht_oper,
struct cfg80211_chan_def *chandef)
@@ -2373,6 +2440,39 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
cfg80211_chandef_create(chandef, control_chan, channel_type);
}
+void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
+ const struct ieee80211_vht_operation *oper,
+ struct cfg80211_chan_def *chandef)
+{
+ if (!oper)
+ return;
+
+ chandef->chan = control_chan;
+
+ switch (oper->chan_width) {
+ case IEEE80211_VHT_CHANWIDTH_USE_HT:
+ break;
+ case IEEE80211_VHT_CHANWIDTH_80MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_80;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_160MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_160;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_80P80;
+ break;
+ default:
+ break;
+ }
+
+ chandef->center_freq1 =
+ ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
+ control_chan->band);
+ chandef->center_freq2 =
+ ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
+ control_chan->band);
+}
+
int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
const struct ieee80211_supported_band *sband,
const u8 *srates, int srates_len, u32 *rates)
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index 85f9596da07b..80694d55db74 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -129,10 +129,6 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
if (!vht_cap_ie || !sband->vht_cap.vht_supported)
return;
- /* don't support VHT for TDLS peers for now */
- if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
- return;
-
/*
* A VHT STA must support 40 MHz, but if we verify that here
* then we break a few things - some APs (e.g. Netgear R6300v2
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 75de6fac40d1..9d63d93c836e 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -780,9 +780,8 @@ ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_key *key = tx->key;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme;
int hdrlen;
- u8 *pos;
+ u8 *pos, iv_len = key->conf.iv_len;
if (info->control.hw_key &&
!(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
@@ -790,14 +789,14 @@ ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
return TX_CONTINUE;
}
- if (unlikely(skb_headroom(skb) < cs->hdr_len &&
- pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC)))
+ if (unlikely(skb_headroom(skb) < iv_len &&
+ pskb_expand_head(skb, iv_len, 0, GFP_ATOMIC)))
return TX_DROP;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
- pos = skb_push(skb, cs->hdr_len);
- memmove(pos, pos + cs->hdr_len, hdrlen);
+ pos = skb_push(skb, iv_len);
+ memmove(pos, pos + iv_len, hdrlen);
return TX_CONTINUE;
}
@@ -1217,7 +1216,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
if (!info->control.hw_key)
return TX_DROP;
- if (tx->key->sta->cipher_scheme) {
+ if (tx->key->flags & KEY_FLAG_CIPHER_SCHEME) {
res = ieee80211_crypto_cs_encrypt(tx, skb);
if (res != TX_CONTINUE)
return res;
diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
index b8b95f4027ca..57a26cc90c9f 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -88,7 +88,6 @@ static int amanda_help(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
- struct ts_state ts;
struct nf_conntrack_expect *exp;
struct nf_conntrack_tuple *tuple;
unsigned int dataoff, start, stop, off, i;
@@ -113,23 +112,20 @@ static int amanda_help(struct sk_buff *skb,
return NF_ACCEPT;
}
- memset(&ts, 0, sizeof(ts));
start = skb_find_text(skb, dataoff, skb->len,
- search[SEARCH_CONNECT].ts, &ts);
+ search[SEARCH_CONNECT].ts);
if (start == UINT_MAX)
goto out;
start += dataoff + search[SEARCH_CONNECT].len;
- memset(&ts, 0, sizeof(ts));
stop = skb_find_text(skb, start, skb->len,
- search[SEARCH_NEWLINE].ts, &ts);
+ search[SEARCH_NEWLINE].ts);
if (stop == UINT_MAX)
goto out;
stop += start;
for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) {
- memset(&ts, 0, sizeof(ts));
- off = skb_find_text(skb, start, stop, search[i].ts, &ts);
+ off = skb_find_text(skb, start, stop, search[i].ts);
if (off == UINT_MAX)
continue;
off += start + search[i].len;
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c
index 5699adb97652..0bc3460319c8 100644
--- a/net/netfilter/xt_string.c
+++ b/net/netfilter/xt_string.c
@@ -26,13 +26,12 @@ static bool
string_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_string_info *conf = par->matchinfo;
- struct ts_state state;
bool invert;
invert = conf->u.v1.flags & XT_STRING_FLAG_INVERT;
return (skb_find_text((struct sk_buff *)skb, conf->from_offset,
- conf->to_offset, conf->config, &state)
+ conf->to_offset, conf->config)
!= UINT_MAX) ^ invert;
}
diff --git a/net/sched/em_text.c b/net/sched/em_text.c
index f03c3de16c27..73e2ed576ceb 100644
--- a/net/sched/em_text.c
+++ b/net/sched/em_text.c
@@ -34,7 +34,6 @@ static int em_text_match(struct sk_buff *skb, struct tcf_ematch *m,
{
struct text_match *tm = EM_TEXT_PRIV(m);
int from, to;
- struct ts_state state;
from = tcf_get_base_ptr(skb, tm->from_layer) - skb->data;
from += tm->from_offset;
@@ -42,7 +41,7 @@ static int em_text_match(struct sk_buff *skb, struct tcf_ematch *m,
to = tcf_get_base_ptr(skb, tm->to_layer) - skb->data;
to += tm->to_offset;
- return skb_find_text(skb, from, to, tm->config, &state) != UINT_MAX;
+ return skb_find_text(skb, from, to, tm->config) != UINT_MAX;
}
static int em_text_change(struct net *net, void *data, int len,
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 29c8675f9a11..b13dfb4ff001 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -178,10 +178,18 @@ config CFG80211_WEXT
bool "cfg80211 wireless extensions compatibility"
depends on CFG80211
select WEXT_CORE
+ default y if CFG80211_WEXT_EXPORT
help
Enable this option if you need old userspace for wireless
extensions with cfg80211-based drivers.
+config CFG80211_WEXT_EXPORT
+ bool
+ depends on CFG80211
+ help
+ Drivers should select this option if they require cfg80211's
+ wext compatibility symbols to be exported.
+
config LIB80211
tristate
default n
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index e24fc585c883..1a65662a5d73 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -30,7 +30,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
return;
bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
- WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+ IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY);
if (WARN_ON(!bss))
return;
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 2c52b59e43f3..7aae329e2b4e 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -229,7 +229,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
return -EALREADY;
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
- WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+ IEEE80211_BSS_TYPE_ESS,
+ IEEE80211_PRIVACY_ANY);
if (!req.bss)
return -ENOENT;
@@ -296,7 +297,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
rdev->wiphy.vht_capa_mod_mask);
req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
- WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+ IEEE80211_BSS_TYPE_ESS,
+ IEEE80211_PRIVACY_ANY);
if (!req->bss)
return -ENOENT;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d78fd8b54515..f60ee5b45c0c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -399,6 +399,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
+ [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
};
/* policy for the key attributes */
@@ -1098,8 +1099,6 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
return -ENOBUFS;
- /* TODO: send wowlan net detect */
-
nla_nest_end(msg, nl_wowlan);
return 0;
@@ -2668,7 +2667,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
wdev = rdev_add_virtual_intf(rdev,
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
- type, err ? NULL : &flags, &params);
+ NET_NAME_USER, type, err ? NULL : &flags,
+ &params);
if (WARN_ON(!wdev)) {
nlmsg_free(msg);
return -EPROTO;
@@ -4958,7 +4958,10 @@ static int parse_reg_rule(struct nlattr *tb[],
static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
{
char *data = NULL;
+ bool is_indoor;
enum nl80211_user_reg_hint_type user_reg_hint_type;
+ u32 owner_nlportid;
+
/*
* You should only get this when cfg80211 hasn't yet initialized
@@ -4984,7 +4987,15 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
return regulatory_hint_user(data, user_reg_hint_type);
case NL80211_USER_REG_HINT_INDOOR:
- return regulatory_hint_indoor_user();
+ if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+ owner_nlportid = info->snd_portid;
+ is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
+ } else {
+ owner_nlportid = 0;
+ is_indoor = true;
+ }
+
+ return regulatory_hint_indoor(is_indoor, owner_nlportid);
default:
return -EINVAL;
}
@@ -5265,7 +5276,7 @@ do { \
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
0, 65535, mask,
NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
- FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 1, 0xffffffff,
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff,
mask, NL80211_MESHCONF_PLINK_TIMEOUT,
nla_get_u32);
if (mask_out)
@@ -7265,8 +7276,18 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
break;
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_40:
- if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)
- break;
+ if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
+ return -EINVAL;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_160:
+ if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
+ return -EINVAL;
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_VHT_IBSS))
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
@@ -7379,8 +7400,8 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
static struct sk_buff *
__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
- int approxlen, u32 portid, u32 seq,
- enum nl80211_commands cmd,
+ struct wireless_dev *wdev, int approxlen,
+ u32 portid, u32 seq, enum nl80211_commands cmd,
enum nl80211_attrs attr,
const struct nl80211_vendor_cmd_info *info,
gfp_t gfp)
@@ -7411,6 +7432,16 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
goto nla_put_failure;
}
+ if (wdev) {
+ if (nla_put_u64(skb, NL80211_ATTR_WDEV,
+ wdev_id(wdev)))
+ goto nla_put_failure;
+ if (wdev->netdev &&
+ nla_put_u32(skb, NL80211_ATTR_IFINDEX,
+ wdev->netdev->ifindex))
+ goto nla_put_failure;
+ }
+
data = nla_nest_start(skb, attr);
((void **)skb->cb)[0] = rdev;
@@ -7425,6 +7456,7 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
}
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
enum nl80211_commands cmd,
enum nl80211_attrs attr,
int vendor_event_idx,
@@ -7450,7 +7482,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
return NULL;
}
- return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
+ return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
cmd, attr, info, gfp);
}
EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
@@ -8798,6 +8830,9 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg,
if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval))
return -ENOBUFS;
+ if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
+ return -ENOBUFS;
+
freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
if (!freqs)
return -ENOBUFS;
@@ -9084,6 +9119,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
int err, i;
bool prev_enabled = rdev->wiphy.wowlan_config;
+ bool regular = false;
if (!wowlan)
return -EOPNOTSUPP;
@@ -9111,12 +9147,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
return -EINVAL;
new_triggers.disconnect = true;
+ regular = true;
}
if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
return -EINVAL;
new_triggers.magic_pkt = true;
+ regular = true;
}
if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
@@ -9126,24 +9164,28 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
return -EINVAL;
new_triggers.gtk_rekey_failure = true;
+ regular = true;
}
if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
return -EINVAL;
new_triggers.eap_identity_req = true;
+ regular = true;
}
if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
return -EINVAL;
new_triggers.four_way_handshake = true;
+ regular = true;
}
if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
return -EINVAL;
new_triggers.rfkill_release = true;
+ regular = true;
}
if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
@@ -9152,6 +9194,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
int rem, pat_len, mask_len, pkt_offset;
struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
+ regular = true;
+
nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
rem)
n_patterns++;
@@ -9213,6 +9257,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
}
if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
+ regular = true;
err = nl80211_parse_wowlan_tcp(
rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
&new_triggers);
@@ -9221,6 +9266,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
}
if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
+ regular = true;
err = nl80211_parse_wowlan_nd(
rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
&new_triggers);
@@ -9228,6 +9274,17 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
goto error;
}
+ /* The 'any' trigger means the device continues operating more or less
+ * as in its normal operation mode and wakes up the host on most of the
+ * normal interrupts (like packet RX, ...)
+ * It therefore makes little sense to combine with the more constrained
+ * wakeup trigger modes.
+ */
+ if (new_triggers.any && regular) {
+ err = -EINVAL;
+ goto error;
+ }
+
ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
if (!ntrig) {
err = -ENOMEM;
@@ -9896,7 +9953,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
if (WARN_ON(!rdev->cur_cmd_info))
return NULL;
- return __cfg80211_alloc_vendor_skb(rdev, approxlen,
+ return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
rdev->cur_cmd_info->snd_portid,
rdev->cur_cmd_info->snd_seq,
cmd, attr, NULL, GFP_KERNEL);
@@ -12767,6 +12824,11 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
rcu_read_unlock();
+ /*
+ * It is possible that the user space process that is controlling the
+ * indoor setting disappeared, so notify the regulatory core.
+ */
+ regulatory_netlink_notify(notify->portid);
return NOTIFY_OK;
}
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 35cfb7134bdb..c6e83a7468c0 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -35,13 +35,14 @@ static inline void rdev_set_wakeup(struct cfg80211_registered_device *rdev,
static inline struct wireless_dev
*rdev_add_virtual_intf(struct cfg80211_registered_device *rdev, char *name,
+ unsigned char name_assign_type,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
struct wireless_dev *ret;
trace_rdev_add_virtual_intf(&rdev->wiphy, name, type);
- ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, type, flags,
- params);
+ ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, name_assign_type,
+ type, flags, params);
trace_rdev_return_wdev(&rdev->wiphy, ret);
return ret;
}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index b586d0dcb09e..8c6cf52b9f1d 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -82,17 +82,12 @@
* be intersected with the current one.
* @REG_REQ_ALREADY_SET: the regulatory request will not change the current
* regulatory settings, and no further processing is required.
- * @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no
- * further processing is required, i.e., not need to update last_request
- * etc. This should be used for user hints that do not provide an alpha2
- * but some other type of regulatory hint, i.e., indoor operation.
*/
enum reg_request_treatment {
REG_REQ_OK,
REG_REQ_IGNORE,
REG_REQ_INTERSECT,
REG_REQ_ALREADY_SET,
- REG_REQ_USER_HINT_HANDLED,
};
static struct regulatory_request core_request_world = {
@@ -133,9 +128,12 @@ static int reg_num_devs_support_basehint;
* State variable indicating if the platform on which the devices
* are attached is operating in an indoor environment. The state variable
* is relevant for all registered devices.
- * (protected by RTNL)
*/
static bool reg_is_indoor;
+static spinlock_t reg_indoor_lock;
+
+/* Used to track the userspace process controlling the indoor setting */
+static u32 reg_is_indoor_portid;
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
{
@@ -554,6 +552,9 @@ reg_call_crda(struct regulatory_request *request)
{
if (call_crda(request->alpha2))
return REG_REQ_IGNORE;
+
+ queue_delayed_work(system_power_efficient_wq,
+ &reg_timeout, msecs_to_jiffies(3142));
return REG_REQ_OK;
}
@@ -1248,13 +1249,6 @@ static bool reg_request_cell_base(struct regulatory_request *request)
return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
}
-static bool reg_request_indoor(struct regulatory_request *request)
-{
- if (request->initiator != NL80211_REGDOM_SET_BY_USER)
- return false;
- return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
-}
-
bool reg_last_request_cell_base(void)
{
return reg_request_cell_base(get_last_request());
@@ -1800,8 +1794,7 @@ static void reg_set_request_processed(void)
need_more_processing = true;
spin_unlock(&reg_requests_lock);
- if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
- cancel_delayed_work(&reg_timeout);
+ cancel_delayed_work(&reg_timeout);
if (need_more_processing)
schedule_work(&reg_work);
@@ -1833,11 +1826,6 @@ __reg_process_hint_user(struct regulatory_request *user_request)
{
struct regulatory_request *lr = get_last_request();
- if (reg_request_indoor(user_request)) {
- reg_is_indoor = true;
- return REG_REQ_USER_HINT_HANDLED;
- }
-
if (reg_request_cell_base(user_request))
return reg_ignore_cell_hint(user_request);
@@ -1885,8 +1873,7 @@ reg_process_hint_user(struct regulatory_request *user_request)
treatment = __reg_process_hint_user(user_request);
if (treatment == REG_REQ_IGNORE ||
- treatment == REG_REQ_ALREADY_SET ||
- treatment == REG_REQ_USER_HINT_HANDLED) {
+ treatment == REG_REQ_ALREADY_SET) {
reg_free_request(user_request);
return treatment;
}
@@ -1947,7 +1934,6 @@ reg_process_hint_driver(struct wiphy *wiphy,
case REG_REQ_OK:
break;
case REG_REQ_IGNORE:
- case REG_REQ_USER_HINT_HANDLED:
reg_free_request(driver_request);
return treatment;
case REG_REQ_INTERSECT:
@@ -2047,7 +2033,6 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
case REG_REQ_OK:
break;
case REG_REQ_IGNORE:
- case REG_REQ_USER_HINT_HANDLED:
/* fall through */
case REG_REQ_ALREADY_SET:
reg_free_request(country_ie_request);
@@ -2086,11 +2071,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
case NL80211_REGDOM_SET_BY_USER:
treatment = reg_process_hint_user(reg_request);
if (treatment == REG_REQ_IGNORE ||
- treatment == REG_REQ_ALREADY_SET ||
- treatment == REG_REQ_USER_HINT_HANDLED)
+ treatment == REG_REQ_ALREADY_SET)
return;
- queue_delayed_work(system_power_efficient_wq,
- &reg_timeout, msecs_to_jiffies(3142));
return;
case NL80211_REGDOM_SET_BY_DRIVER:
if (!wiphy)
@@ -2177,6 +2159,13 @@ static void reg_process_pending_hints(void)
}
reg_process_hint(reg_request);
+
+ lr = get_last_request();
+
+ spin_lock(&reg_requests_lock);
+ if (!list_empty(&reg_requests_list) && lr && lr->processed)
+ schedule_work(&reg_work);
+ spin_unlock(&reg_requests_lock);
}
/* Processes beacon hints -- this has nothing to do with country IEs */
@@ -2309,22 +2298,50 @@ int regulatory_hint_user(const char *alpha2,
return 0;
}
-int regulatory_hint_indoor_user(void)
+int regulatory_hint_indoor(bool is_indoor, u32 portid)
{
- struct regulatory_request *request;
+ spin_lock(&reg_indoor_lock);
- request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
- if (!request)
- return -ENOMEM;
+ /* It is possible that more than one user space process is trying to
+ * configure the indoor setting. To handle such cases, clear the indoor
+ * setting in case that some process does not think that the device
+ * is operating in an indoor environment. In addition, if a user space
+ * process indicates that it is controlling the indoor setting, save its
+ * portid, i.e., make it the owner.
+ */
+ reg_is_indoor = is_indoor;
+ if (reg_is_indoor) {
+ if (!reg_is_indoor_portid)
+ reg_is_indoor_portid = portid;
+ } else {
+ reg_is_indoor_portid = 0;
+ }
- request->wiphy_idx = WIPHY_IDX_INVALID;
- request->initiator = NL80211_REGDOM_SET_BY_USER;
- request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR;
- queue_regulatory_request(request);
+ spin_unlock(&reg_indoor_lock);
+
+ if (!is_indoor)
+ reg_check_channels();
return 0;
}
+void regulatory_netlink_notify(u32 portid)
+{
+ spin_lock(&reg_indoor_lock);
+
+ if (reg_is_indoor_portid != portid) {
+ spin_unlock(&reg_indoor_lock);
+ return;
+ }
+
+ reg_is_indoor = false;
+ reg_is_indoor_portid = 0;
+
+ spin_unlock(&reg_indoor_lock);
+
+ reg_check_channels();
+}
+
/* Driver hints */
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
{
@@ -2486,13 +2503,22 @@ static void restore_regulatory_settings(bool reset_user)
char alpha2[2];
char world_alpha2[2];
struct reg_beacon *reg_beacon, *btmp;
- struct regulatory_request *reg_request, *tmp;
LIST_HEAD(tmp_reg_req_list);
struct cfg80211_registered_device *rdev;
ASSERT_RTNL();
- reg_is_indoor = false;
+ /*
+ * Clear the indoor setting in case that it is not controlled by user
+ * space, as otherwise there is no guarantee that the device is still
+ * operating in an indoor environment.
+ */
+ spin_lock(&reg_indoor_lock);
+ if (reg_is_indoor && !reg_is_indoor_portid) {
+ reg_is_indoor = false;
+ reg_check_channels();
+ }
+ spin_unlock(&reg_indoor_lock);
reset_regdomains(true, &world_regdom);
restore_alpha2(alpha2, reset_user);
@@ -2504,11 +2530,7 @@ static void restore_regulatory_settings(bool reset_user)
* settings.
*/
spin_lock(&reg_requests_lock);
- list_for_each_entry_safe(reg_request, tmp, &reg_requests_list, list) {
- if (reg_request->initiator != NL80211_REGDOM_SET_BY_USER)
- continue;
- list_move_tail(&reg_request->list, &tmp_reg_req_list);
- }
+ list_splice_tail_init(&reg_requests_list, &tmp_reg_req_list);
spin_unlock(&reg_requests_lock);
/* Clear beacon hints */
@@ -3089,6 +3111,7 @@ int __init regulatory_init(void)
spin_lock_init(&reg_requests_lock);
spin_lock_init(&reg_pending_beacons_lock);
+ spin_lock_init(&reg_indoor_lock);
reg_regdb_size_check();
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 4b45d6e61d24..a2c4e16459da 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -25,7 +25,20 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy);
int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type);
-int regulatory_hint_indoor_user(void);
+
+/**
+ * regulatory_hint_indoor - hint operation in indoor env. or not
+ * @is_indoor: if true indicates that user space thinks that the
+ * device is operating in an indoor environment.
+ * @portid: the netlink port ID on which the hint was given.
+ */
+int regulatory_hint_indoor(bool is_indoor, u32 portid);
+
+/**
+ * regulatory_netlink_notify - notify on released netlink socket
+ * @portid: the netlink socket port ID
+ */
+void regulatory_netlink_notify(u32 portid);
void wiphy_regulatory_register(struct wiphy *wiphy);
void wiphy_regulatory_deregister(struct wiphy *wiphy);
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index c705c3e2b751..3a50aa2553bf 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -531,24 +531,78 @@ static int cmp_bss(struct cfg80211_bss *a,
}
}
+static bool cfg80211_bss_type_match(u16 capability,
+ enum ieee80211_band band,
+ enum ieee80211_bss_type bss_type)
+{
+ bool ret = true;
+ u16 mask, val;
+
+ if (bss_type == IEEE80211_BSS_TYPE_ANY)
+ return ret;
+
+ if (band == IEEE80211_BAND_60GHZ) {
+ mask = WLAN_CAPABILITY_DMG_TYPE_MASK;
+ switch (bss_type) {
+ case IEEE80211_BSS_TYPE_ESS:
+ val = WLAN_CAPABILITY_DMG_TYPE_AP;
+ break;
+ case IEEE80211_BSS_TYPE_PBSS:
+ val = WLAN_CAPABILITY_DMG_TYPE_PBSS;
+ break;
+ case IEEE80211_BSS_TYPE_IBSS:
+ val = WLAN_CAPABILITY_DMG_TYPE_IBSS;
+ break;
+ default:
+ return false;
+ }
+ } else {
+ mask = WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS;
+ switch (bss_type) {
+ case IEEE80211_BSS_TYPE_ESS:
+ val = WLAN_CAPABILITY_ESS;
+ break;
+ case IEEE80211_BSS_TYPE_IBSS:
+ val = WLAN_CAPABILITY_IBSS;
+ break;
+ case IEEE80211_BSS_TYPE_MBSS:
+ val = 0;
+ break;
+ default:
+ return false;
+ }
+ }
+
+ ret = ((capability & mask) == val);
+ return ret;
+}
+
/* Returned bss is reference counted and must be cleaned up appropriately. */
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
struct ieee80211_channel *channel,
const u8 *bssid,
const u8 *ssid, size_t ssid_len,
- u16 capa_mask, u16 capa_val)
+ enum ieee80211_bss_type bss_type,
+ enum ieee80211_privacy privacy)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_internal_bss *bss, *res = NULL;
unsigned long now = jiffies;
+ int bss_privacy;
- trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask,
- capa_val);
+ trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, bss_type,
+ privacy);
spin_lock_bh(&rdev->bss_lock);
list_for_each_entry(bss, &rdev->bss_list, list) {
- if ((bss->pub.capability & capa_mask) != capa_val)
+ if (!cfg80211_bss_type_match(bss->pub.capability,
+ bss->pub.channel->band, bss_type))
+ continue;
+
+ bss_privacy = (bss->pub.capability & WLAN_CAPABILITY_PRIVACY);
+ if ((privacy == IEEE80211_PRIVACY_ON && !bss_privacy) ||
+ (privacy == IEEE80211_PRIVACY_OFF && bss_privacy))
continue;
if (channel && bss->pub.channel != channel)
continue;
@@ -896,6 +950,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
struct cfg80211_bss_ies *ies;
struct ieee80211_channel *channel;
struct cfg80211_internal_bss tmp = {}, *res;
+ int bss_type;
bool signal_valid;
if (WARN_ON(!wiphy))
@@ -950,8 +1005,15 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
if (!res)
return NULL;
- if (res->pub.capability & WLAN_CAPABILITY_ESS)
- regulatory_hint_found_beacon(wiphy, channel, gfp);
+ if (channel->band == IEEE80211_BAND_60GHZ) {
+ bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK;
+ if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP ||
+ bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS)
+ regulatory_hint_found_beacon(wiphy, channel, gfp);
+ } else {
+ if (res->pub.capability & WLAN_CAPABILITY_ESS)
+ regulatory_hint_found_beacon(wiphy, channel, gfp);
+ }
trace_cfg80211_return_bss(&res->pub);
/* cfg80211_bss_update gives us a referenced result */
@@ -973,6 +1035,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
bool signal_valid;
size_t ielen = len - offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
+ int bss_type;
BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
offsetof(struct ieee80211_mgmt, u.beacon.variable));
@@ -1025,8 +1088,15 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
if (!res)
return NULL;
- if (res->pub.capability & WLAN_CAPABILITY_ESS)
- regulatory_hint_found_beacon(wiphy, channel, gfp);
+ if (channel->band == IEEE80211_BAND_60GHZ) {
+ bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK;
+ if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP ||
+ bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS)
+ regulatory_hint_found_beacon(wiphy, channel, gfp);
+ } else {
+ if (res->pub.capability & WLAN_CAPABILITY_ESS)
+ regulatory_hint_found_beacon(wiphy, channel, gfp);
+ }
trace_cfg80211_return_bss(&res->pub);
/* cfg80211_bss_update gives us a referenced result */
@@ -1237,17 +1307,17 @@ int cfg80211_wext_siwscan(struct net_device *dev,
kfree(creq);
return err;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
+EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan);
-static void ieee80211_scan_add_ies(struct iw_request_info *info,
- const struct cfg80211_bss_ies *ies,
- char **current_ev, char *end_buf)
+static char *ieee80211_scan_add_ies(struct iw_request_info *info,
+ const struct cfg80211_bss_ies *ies,
+ char *current_ev, char *end_buf)
{
const u8 *pos, *end, *next;
struct iw_event iwe;
if (!ies)
- return;
+ return current_ev;
/*
* If needed, fragment the IEs buffer (at IE boundaries) into short
@@ -1264,10 +1334,11 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = next - pos;
- *current_ev = iwe_stream_add_point(info, *current_ev,
- end_buf, &iwe,
- (void *)pos);
-
+ current_ev = iwe_stream_add_point_check(info, current_ev,
+ end_buf, &iwe,
+ (void *)pos);
+ if (IS_ERR(current_ev))
+ return current_ev;
pos = next;
}
@@ -1275,10 +1346,14 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVGENIE;
iwe.u.data.length = end - pos;
- *current_ev = iwe_stream_add_point(info, *current_ev,
- end_buf, &iwe,
- (void *)pos);
+ current_ev = iwe_stream_add_point_check(info, current_ev,
+ end_buf, &iwe,
+ (void *)pos);
+ if (IS_ERR(current_ev))
+ return current_ev;
}
+
+ return current_ev;
}
static char *
@@ -1289,7 +1364,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
const struct cfg80211_bss_ies *ies;
struct iw_event iwe;
const u8 *ie;
- u8 *buf, *cfg, *p;
+ u8 buf[50];
+ u8 *cfg, *p, *tmp;
int rem, i, sig;
bool ismesh = false;
@@ -1297,22 +1373,28 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_ADDR_LEN);
+ current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
+ IW_EV_ADDR_LEN);
+ if (IS_ERR(current_ev))
+ return current_ev;
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_FREQ_LEN);
+ current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
+ IW_EV_FREQ_LEN);
+ if (IS_ERR(current_ev))
+ return current_ev;
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = bss->pub.channel->center_freq;
iwe.u.freq.e = 6;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_FREQ_LEN);
+ current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
+ IW_EV_FREQ_LEN);
+ if (IS_ERR(current_ev))
+ return current_ev;
if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
memset(&iwe, 0, sizeof(iwe));
@@ -1341,8 +1423,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
/* not reached */
break;
}
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
+ current_ev = iwe_stream_add_event_check(info, current_ev,
+ end_buf, &iwe,
+ IW_EV_QUAL_LEN);
+ if (IS_ERR(current_ev))
+ return current_ev;
}
memset(&iwe, 0, sizeof(iwe));
@@ -1352,8 +1437,10 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, "");
+ current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
+ &iwe, "");
+ if (IS_ERR(current_ev))
+ return current_ev;
rcu_read_lock();
ies = rcu_dereference(bss->pub.ies);
@@ -1371,66 +1458,91 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
iwe.cmd = SIOCGIWESSID;
iwe.u.data.length = ie[1];
iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, (u8 *)ie + 2);
+ current_ev = iwe_stream_add_point_check(info,
+ current_ev,
+ end_buf, &iwe,
+ (u8 *)ie + 2);
+ if (IS_ERR(current_ev))
+ goto unlock;
break;
case WLAN_EID_MESH_ID:
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWESSID;
iwe.u.data.length = ie[1];
iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, (u8 *)ie + 2);
+ current_ev = iwe_stream_add_point_check(info,
+ current_ev,
+ end_buf, &iwe,
+ (u8 *)ie + 2);
+ if (IS_ERR(current_ev))
+ goto unlock;
break;
case WLAN_EID_MESH_CONFIG:
ismesh = true;
if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
break;
- buf = kmalloc(50, GFP_ATOMIC);
- if (!buf)
- break;
cfg = (u8 *)ie + 2;
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVCUSTOM;
sprintf(buf, "Mesh Network Path Selection Protocol ID: "
"0x%02X", cfg[0]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
+ current_ev = iwe_stream_add_point_check(info,
+ current_ev,
+ end_buf,
+ &iwe, buf);
+ if (IS_ERR(current_ev))
+ goto unlock;
sprintf(buf, "Path Selection Metric ID: 0x%02X",
cfg[1]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
+ current_ev = iwe_stream_add_point_check(info,
+ current_ev,
+ end_buf,
+ &iwe, buf);
+ if (IS_ERR(current_ev))
+ goto unlock;
sprintf(buf, "Congestion Control Mode ID: 0x%02X",
cfg[2]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
+ current_ev = iwe_stream_add_point_check(info,
+ current_ev,
+ end_buf,
+ &iwe, buf);
+ if (IS_ERR(current_ev))
+ goto unlock;
sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
+ current_ev = iwe_stream_add_point_check(info,
+ current_ev,
+ end_buf,
+ &iwe, buf);
+ if (IS_ERR(current_ev))
+ goto unlock;
sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
+ current_ev = iwe_stream_add_point_check(info,
+ current_ev,
+ end_buf,
+ &iwe, buf);
+ if (IS_ERR(current_ev))
+ goto unlock;
sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
+ current_ev = iwe_stream_add_point_check(info,
+ current_ev,
+ end_buf,
+ &iwe, buf);
+ if (IS_ERR(current_ev))
+ goto unlock;
sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
- kfree(buf);
+ current_ev = iwe_stream_add_point_check(info,
+ current_ev,
+ end_buf,
+ &iwe, buf);
+ if (IS_ERR(current_ev))
+ goto unlock;
break;
case WLAN_EID_SUPP_RATES:
case WLAN_EID_EXT_SUPP_RATES:
@@ -1445,8 +1557,14 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
for (i = 0; i < ie[1]; i++) {
iwe.u.bitrate.value =
((ie[i + 2] & 0x7f) * 500000);
+ tmp = p;
p = iwe_stream_add_value(info, current_ev, p,
- end_buf, &iwe, IW_EV_PARAM_LEN);
+ end_buf, &iwe,
+ IW_EV_PARAM_LEN);
+ if (p == tmp) {
+ current_ev = ERR_PTR(-E2BIG);
+ goto unlock;
+ }
}
current_ev = p;
break;
@@ -1465,31 +1583,35 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
iwe.u.mode = IW_MODE_MASTER;
else
iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- buf = kmalloc(31, GFP_ATOMIC);
- if (buf) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, buf);
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, " Last beacon: %ums ago",
- elapsed_jiffies_msecs(bss->ts));
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf, &iwe, buf);
- kfree(buf);
+ current_ev = iwe_stream_add_event_check(info, current_ev,
+ end_buf, &iwe,
+ IW_EV_UINT_LEN);
+ if (IS_ERR(current_ev))
+ goto unlock;
}
- ieee80211_scan_add_ies(info, ies, &current_ev, end_buf);
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
+ &iwe, buf);
+ if (IS_ERR(current_ev))
+ goto unlock;
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, " Last beacon: %ums ago",
+ elapsed_jiffies_msecs(bss->ts));
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point_check(info, current_ev,
+ end_buf, &iwe, buf);
+ if (IS_ERR(current_ev))
+ goto unlock;
+
+ current_ev = ieee80211_scan_add_ies(info, ies, current_ev, end_buf);
+
+ unlock:
rcu_read_unlock();
-
return current_ev;
}
@@ -1501,19 +1623,27 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
char *current_ev = buf;
char *end_buf = buf + len;
struct cfg80211_internal_bss *bss;
+ int err = 0;
spin_lock_bh(&rdev->bss_lock);
cfg80211_bss_expire(rdev);
list_for_each_entry(bss, &rdev->bss_list, list) {
if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
- spin_unlock_bh(&rdev->bss_lock);
- return -E2BIG;
+ err = -E2BIG;
+ break;
}
current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
current_ev, end_buf);
+ if (IS_ERR(current_ev)) {
+ err = PTR_ERR(current_ev);
+ break;
+ }
}
spin_unlock_bh(&rdev->bss_lock);
+
+ if (err)
+ return err;
return current_ev - buf;
}
@@ -1545,5 +1675,5 @@ int cfg80211_wext_giwscan(struct net_device *dev,
return res;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan);
+EXPORT_WEXT_HANDLER(cfg80211_wext_giwscan);
#endif
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 0ab3711c79a0..ea1da6621ff0 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -257,19 +257,15 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_bss *bss;
- u16 capa = WLAN_CAPABILITY_ESS;
ASSERT_WDEV_LOCK(wdev);
- if (wdev->conn->params.privacy)
- capa |= WLAN_CAPABILITY_PRIVACY;
-
bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel,
wdev->conn->params.bssid,
wdev->conn->params.ssid,
wdev->conn->params.ssid_len,
- WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
- capa);
+ IEEE80211_BSS_TYPE_ESS,
+ IEEE80211_PRIVACY(wdev->conn->params.privacy));
if (!bss)
return NULL;
@@ -637,8 +633,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
wdev->ssid, wdev->ssid_len,
- WLAN_CAPABILITY_ESS,
- WLAN_CAPABILITY_ESS);
+ IEEE80211_BSS_TYPE_ESS,
+ IEEE80211_PRIVACY_ANY);
if (bss)
cfg80211_hold_bss(bss_from_pub(bss));
}
@@ -795,8 +791,8 @@ void cfg80211_roamed(struct net_device *dev,
struct cfg80211_bss *bss;
bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
- wdev->ssid_len, WLAN_CAPABILITY_ESS,
- WLAN_CAPABILITY_ESS);
+ wdev->ssid_len,
+ IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
if (WARN_ON(!bss))
return;
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index b17b3692f8c2..e4e39143728c 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -627,6 +627,7 @@ DECLARE_EVENT_CLASS(station_add_change,
__field(u8, plink_state)
__field(u8, uapsd_queues)
__array(u8, ht_capa, (int)sizeof(struct ieee80211_ht_cap))
+ __array(char, vlan, IFNAMSIZ)
),
TP_fast_assign(
WIPHY_ASSIGN;
@@ -644,16 +645,19 @@ DECLARE_EVENT_CLASS(station_add_change,
if (params->ht_capa)
memcpy(__entry->ht_capa, params->ht_capa,
sizeof(struct ieee80211_ht_cap));
+ memset(__entry->vlan, 0, sizeof(__entry->vlan));
+ if (params->vlan)
+ memcpy(__entry->vlan, params->vlan->name, IFNAMSIZ);
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
", station flags mask: %u, station flags set: %u, "
"station modify mask: %u, listen interval: %d, aid: %u, "
- "plink action: %u, plink state: %u, uapsd queues: %u",
+ "plink action: %u, plink state: %u, uapsd queues: %u, vlan:%s",
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac),
__entry->sta_flags_mask, __entry->sta_flags_set,
__entry->sta_modify_mask, __entry->listen_interval,
__entry->aid, __entry->plink_action, __entry->plink_state,
- __entry->uapsd_queues)
+ __entry->uapsd_queues, __entry->vlan)
);
DEFINE_EVENT(station_add_change, rdev_add_station,
@@ -2636,28 +2640,30 @@ DEFINE_EVENT(wiphy_only_evt, cfg80211_sched_scan_stopped,
TRACE_EVENT(cfg80211_get_bss,
TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
const u8 *bssid, const u8 *ssid, size_t ssid_len,
- u16 capa_mask, u16 capa_val),
- TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, capa_mask, capa_val),
+ enum ieee80211_bss_type bss_type,
+ enum ieee80211_privacy privacy),
+ TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, bss_type, privacy),
TP_STRUCT__entry(
WIPHY_ENTRY
CHAN_ENTRY
MAC_ENTRY(bssid)
__dynamic_array(u8, ssid, ssid_len)
- __field(u16, capa_mask)
- __field(u16, capa_val)
+ __field(enum ieee80211_bss_type, bss_type)
+ __field(enum ieee80211_privacy, privacy)
),
TP_fast_assign(
WIPHY_ASSIGN;
CHAN_ASSIGN(channel);
MAC_ASSIGN(bssid, bssid);
memcpy(__get_dynamic_array(ssid), ssid, ssid_len);
- __entry->capa_mask = capa_mask;
- __entry->capa_val = capa_val;
- ),
- TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT ", buf: %#.2x, "
- "capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG,
- MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0],
- __entry->capa_mask, __entry->capa_val)
+ __entry->bss_type = bss_type;
+ __entry->privacy = privacy;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT
+ ", buf: %#.2x, bss_type: %d, privacy: %d",
+ WIPHY_PR_ARG, CHAN_PR_ARG, MAC_PR_ARG(bssid),
+ ((u8 *)__get_dynamic_array(ssid))[0], __entry->bss_type,
+ __entry->privacy)
);
TRACE_EVENT(cfg80211_inform_bss_width_frame,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 6903dbdcb8c1..f218b151530a 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1296,6 +1296,7 @@ bool ieee80211_operating_class_to_band(u8 operating_class,
switch (operating_class) {
case 112:
case 115 ... 127:
+ case 128 ... 130:
*band = IEEE80211_BAND_5GHZ;
return true;
case 81:
@@ -1313,6 +1314,135 @@ bool ieee80211_operating_class_to_band(u8 operating_class,
}
EXPORT_SYMBOL(ieee80211_operating_class_to_band);
+bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
+ u8 *op_class)
+{
+ u8 vht_opclass;
+ u16 freq = chandef->center_freq1;
+
+ if (freq >= 2412 && freq <= 2472) {
+ if (chandef->width > NL80211_CHAN_WIDTH_40)
+ return false;
+
+ /* 2.407 GHz, channels 1..13 */
+ if (chandef->width == NL80211_CHAN_WIDTH_40) {
+ if (freq > chandef->chan->center_freq)
+ *op_class = 83; /* HT40+ */
+ else
+ *op_class = 84; /* HT40- */
+ } else {
+ *op_class = 81;
+ }
+
+ return true;
+ }
+
+ if (freq == 2484) {
+ if (chandef->width > NL80211_CHAN_WIDTH_40)
+ return false;
+
+ *op_class = 82; /* channel 14 */
+ return true;
+ }
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_80:
+ vht_opclass = 128;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ vht_opclass = 129;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ vht_opclass = 130;
+ break;
+ case NL80211_CHAN_WIDTH_10:
+ case NL80211_CHAN_WIDTH_5:
+ return false; /* unsupported for now */
+ default:
+ vht_opclass = 0;
+ break;
+ }
+
+ /* 5 GHz, channels 36..48 */
+ if (freq >= 5180 && freq <= 5240) {
+ if (vht_opclass) {
+ *op_class = vht_opclass;
+ } else if (chandef->width == NL80211_CHAN_WIDTH_40) {
+ if (freq > chandef->chan->center_freq)
+ *op_class = 116;
+ else
+ *op_class = 117;
+ } else {
+ *op_class = 115;
+ }
+
+ return true;
+ }
+
+ /* 5 GHz, channels 52..64 */
+ if (freq >= 5260 && freq <= 5320) {
+ if (vht_opclass) {
+ *op_class = vht_opclass;
+ } else if (chandef->width == NL80211_CHAN_WIDTH_40) {
+ if (freq > chandef->chan->center_freq)
+ *op_class = 119;
+ else
+ *op_class = 120;
+ } else {
+ *op_class = 118;
+ }
+
+ return true;
+ }
+
+ /* 5 GHz, channels 100..144 */
+ if (freq >= 5500 && freq <= 5720) {
+ if (vht_opclass) {
+ *op_class = vht_opclass;
+ } else if (chandef->width == NL80211_CHAN_WIDTH_40) {
+ if (freq > chandef->chan->center_freq)
+ *op_class = 122;
+ else
+ *op_class = 123;
+ } else {
+ *op_class = 121;
+ }
+
+ return true;
+ }
+
+ /* 5 GHz, channels 149..169 */
+ if (freq >= 5745 && freq <= 5845) {
+ if (vht_opclass) {
+ *op_class = vht_opclass;
+ } else if (chandef->width == NL80211_CHAN_WIDTH_40) {
+ if (freq > chandef->chan->center_freq)
+ *op_class = 126;
+ else
+ *op_class = 127;
+ } else if (freq <= 5805) {
+ *op_class = 124;
+ } else {
+ *op_class = 125;
+ }
+
+ return true;
+ }
+
+ /* 56.16 GHz, channel 1..4 */
+ if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
+ if (chandef->width >= NL80211_CHAN_WIDTH_40)
+ return false;
+
+ *op_class = 180;
+ return true;
+ }
+
+ /* not supported yet */
+ return false;
+}
+EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
+
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
u32 beacon_int)
{
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 5b24d39d7903..fff1bef6ed6d 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -63,7 +63,7 @@ int cfg80211_wext_giwname(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwname);
+EXPORT_WEXT_HANDLER(cfg80211_wext_giwname);
int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
u32 *mode, char *extra)
@@ -99,7 +99,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
return cfg80211_change_iface(rdev, dev, type, NULL, &vifparams);
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode);
+EXPORT_WEXT_HANDLER(cfg80211_wext_siwmode);
int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
u32 *mode, char *extra)
@@ -134,7 +134,7 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
}
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode);
+EXPORT_WEXT_HANDLER(cfg80211_wext_giwmode);
int cfg80211_wext_giwrange(struct net_device *dev,
@@ -248,7 +248,7 @@ int cfg80211_wext_giwrange(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
+EXPORT_WEXT_HANDLER(cfg80211_wext_giwrange);
/**
@@ -303,7 +303,7 @@ int cfg80211_wext_siwrts(struct net_device *dev,
return err;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts);
+EXPORT_WEXT_HANDLER(cfg80211_wext_siwrts);
int cfg80211_wext_giwrts(struct net_device *dev,
struct iw_request_info *info,
@@ -317,7 +317,7 @@ int cfg80211_wext_giwrts(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts);
+EXPORT_WEXT_HANDLER(cfg80211_wext_giwrts);
int cfg80211_wext_siwfrag(struct net_device *dev,
struct iw_request_info *info,
@@ -343,7 +343,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev,
return err;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag);
+EXPORT_WEXT_HANDLER(cfg80211_wext_siwfrag);
int cfg80211_wext_giwfrag(struct net_device *dev,
struct iw_request_info *info,
@@ -357,7 +357,7 @@ int cfg80211_wext_giwfrag(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag);
+EXPORT_WEXT_HANDLER(cfg80211_wext_giwfrag);
static int cfg80211_wext_siwretry(struct net_device *dev,
struct iw_request_info *info,
@@ -427,7 +427,7 @@ int cfg80211_wext_giwretry(struct net_device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
+EXPORT_WEXT_HANDLER(cfg80211_wext_giwretry);
static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool pairwise,
diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h
index ebcacca2f731..94c7405a5413 100644
--- a/net/wireless/wext-compat.h
+++ b/net/wireless/wext-compat.h
@@ -4,6 +4,12 @@
#include <net/iw_handler.h>
#include <linux/wireless.h>
+#ifdef CONFIG_CFG80211_WEXT_EXPORT
+#define EXPORT_WEXT_HANDLER(h) EXPORT_SYMBOL_GPL(h)
+#else
+#define EXPORT_WEXT_HANDLER(h)
+#endif /* CONFIG_CFG80211_WEXT_EXPORT */
+
int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra);