mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-28 16:53:49 +00:00
Including fixes from bluetooth, netfilter and wireless.
Current release - fix to a fix: - rtnetlink: fix error code in rtnl_newlink() - tipc: fix NULL deref in cleanup_bearer() Current release - regressions: - ip: fix warning about invalid return from in ip_route_input_rcu() Current release - new code bugs: - udp: fix L4 hash after reconnect - eth: lan969x: fix cyclic dependency between modules - eth: bnxt_en: fix potential crash when dumping FW log coredump Previous releases - regressions: - wifi: mac80211: - fix a queue stall in certain cases of channel switch - wake the queues in case of failure in resume - splice: do not checksum AF_UNIX sockets - virtio_net: fix BUG()s in BQL support due to incorrect accounting of purged packets during interface stop - eth: stmmac: fix TSO DMA API mis-usage causing oops - eth: bnxt_en: fixes for HW GRO: GSO type on 5750X chips and oops due to incorrect aggregation ID mask on 5760X chips Previous releases - always broken: - Bluetooth: improve setsockopt() handling of malformed user input - eth: ocelot: fix PTP timestamping in presence of packet loss - ptp: kvm: x86: avoid "fail to initialize ptp_kvm" when simply not supported Signed-off-by: Jakub Kicinski <kuba@kernel.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmdbCXgACgkQMUZtbf5S Irtizg/9GVtTtu0OeQpHlxOpXOdqRciHDHBcjc0+rYihHazA47wtOszPg2BDiebV 1D+uTaPoxuJUZo9jDAGMerUpy6gmC8+4h9gp72oSU9uGNHTrDWsylsn16foFkmpg hMsq+bzYr9ayekIXoI4T//PQ8MO8fqLFPdJmFPIKjkTtsrCzzARck9R4uDlWzrJj v5cQY+q/6qnwZTvvto67ahjdKUw8k3XIRZxLDqrDiW+zUzdk9XRwK46AdP3eybcx OCMHvXmWx6DTbjeEbzhq5YwDGAnBOE9rP4vJmpV9y+PcPDCmPzt7IDNWACcEPHY4 3vuZv3JJP/5MIqGHidDn1JYgWl/Y3iv5ZfKInG585XH+5VWemq3WL1JOS2ua6Xmu hoGhwNTGea4KtCeutE8xSwMSBTxswkdPb93ZFPt28zKAN118chBvGLRv2jepSvQR 3AQhJ9bgGuErHMYh5vdiluRVj/4bwSIFqEH6vr6w9+DUDFiTSKERLXSJ8dc8S+9K ghd/I8POb4VTfjZIyHzo1DJOulPXe84KGMcOuAfh0AV7o5HcuP+oNdR3+qS2Lf+G EByIX8osZsHjqaVr5ba+KnZz2XrdO7mbE54fCKa9ZUwkNIbcCEqOJBqcMlPWxvtK whrGDOS8ifYYK6fL6IFO5CtxBvWmQgMOYV6Sjp9J27PD4jiMrms= =TDKt -----END PGP SIGNATURE----- Merge tag 'net-6.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net Pull networking fixes from Jakub Kicinski: "Including fixes from bluetooth, netfilter and wireless. Current release - fix to a fix: - rtnetlink: fix error code in rtnl_newlink() - tipc: fix NULL deref in cleanup_bearer() Current release - regressions: - ip: fix warning about invalid return from in ip_route_input_rcu() Current release - new code bugs: - udp: fix L4 hash after reconnect - eth: lan969x: fix cyclic dependency between modules - eth: bnxt_en: fix potential crash when dumping FW log coredump Previous releases - regressions: - wifi: mac80211: - fix a queue stall in certain cases of channel switch - wake the queues in case of failure in resume - splice: do not checksum AF_UNIX sockets - virtio_net: fix BUG()s in BQL support due to incorrect accounting of purged packets during interface stop - eth: - stmmac: fix TSO DMA API mis-usage causing oops - bnxt_en: fixes for HW GRO: GSO type on 5750X chips and oops due to incorrect aggregation ID mask on 5760X chips Previous releases - always broken: - Bluetooth: improve setsockopt() handling of malformed user input - eth: ocelot: fix PTP timestamping in presence of packet loss - ptp: kvm: x86: avoid "fail to initialize ptp_kvm" when simply not supported" * tag 'net-6.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (81 commits) net: dsa: tag_ocelot_8021q: fix broken reception net: dsa: microchip: KSZ9896 register regmap alignment to 32 bit boundaries net: renesas: rswitch: fix initial MPIC register setting Bluetooth: btmtk: avoid UAF in btmtk_process_coredump Bluetooth: iso: Fix circular lock in iso_conn_big_sync Bluetooth: iso: Fix circular lock in iso_listen_bis Bluetooth: SCO: Add support for 16 bits transparent voice setting Bluetooth: iso: Fix recursive locking warning Bluetooth: iso: Always release hdev at the end of iso_listen_bis Bluetooth: hci_event: Fix using rcu_read_(un)lock while iterating Bluetooth: hci_core: Fix sleeping function called from invalid context team: Fix feature propagation of NETIF_F_GSO_ENCAP_ALL team: Fix initial vlan_feature set in __team_compute_features bonding: Fix feature propagation of NETIF_F_GSO_ENCAP_ALL bonding: Fix initial {vlan,mpls}_feature set in bond_compute_features net, team, bonding: Add netdev_base_features helper net/sched: netem: account for backlog updates from child qdisc net: dsa: felix: fix stuck CPU-injected packets with short taprio windows splice: do not checksum AF_UNIX sockets net: usb: qmi_wwan: add Telit FE910C04 compositions ...
This commit is contained in:
commit
150b567e0d
@ -2170,6 +2170,12 @@ nexthop_compat_mode - BOOLEAN
|
||||
understands the new API, this sysctl can be disabled to achieve full
|
||||
performance benefits of the new API by disabling the nexthop expansion
|
||||
and extraneous notifications.
|
||||
|
||||
Note that as a backward-compatible mode, dumping of modern features
|
||||
might be incomplete or wrong. For example, resilient groups will not be
|
||||
shown as such, but rather as just a list of next hops. Also weights that
|
||||
do not fit into 8 bits will show incorrectly.
|
||||
|
||||
Default: true (backward compat mode)
|
||||
|
||||
fib_notify_on_flag_change - INTEGER
|
||||
|
@ -15345,7 +15345,7 @@ M: Daniel Machon <daniel.machon@microchip.com>
|
||||
M: UNGLinuxDriver@microchip.com
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/ethernet/microchip/lan969x/*
|
||||
F: drivers/net/ethernet/microchip/sparx5/lan969x/*
|
||||
|
||||
MICROCHIP LCDFB DRIVER
|
||||
M: Nicolas Ferre <nicolas.ferre@microchip.com>
|
||||
@ -16337,6 +16337,7 @@ F: Documentation/networking/
|
||||
F: Documentation/networking/net_cachelines/
|
||||
F: Documentation/process/maintainer-netdev.rst
|
||||
F: Documentation/userspace-api/netlink/
|
||||
F: include/linux/ethtool.h
|
||||
F: include/linux/framer/framer-provider.h
|
||||
F: include/linux/framer/framer.h
|
||||
F: include/linux/in.h
|
||||
@ -16351,6 +16352,7 @@ F: include/linux/rtnetlink.h
|
||||
F: include/linux/seq_file_net.h
|
||||
F: include/linux/skbuff*
|
||||
F: include/net/
|
||||
F: include/uapi/linux/ethtool.h
|
||||
F: include/uapi/linux/genetlink.h
|
||||
F: include/uapi/linux/hsr_netlink.h
|
||||
F: include/uapi/linux/in.h
|
||||
|
@ -395,6 +395,7 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btmtk_data *data = hci_get_priv(hdev);
|
||||
int err;
|
||||
bool complete = false;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) {
|
||||
kfree_skb(skb);
|
||||
@ -416,19 +417,22 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
fallthrough;
|
||||
case HCI_DEVCOREDUMP_ACTIVE:
|
||||
default:
|
||||
/* Mediatek coredump data would be more than MTK_COREDUMP_NUM */
|
||||
if (data->cd_info.cnt >= MTK_COREDUMP_NUM &&
|
||||
skb->len > MTK_COREDUMP_END_LEN)
|
||||
if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN],
|
||||
MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1))
|
||||
complete = true;
|
||||
|
||||
err = hci_devcd_append(hdev, skb);
|
||||
if (err < 0)
|
||||
break;
|
||||
data->cd_info.cnt++;
|
||||
|
||||
/* Mediatek coredump data would be more than MTK_COREDUMP_NUM */
|
||||
if (data->cd_info.cnt > MTK_COREDUMP_NUM &&
|
||||
skb->len > MTK_COREDUMP_END_LEN)
|
||||
if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN],
|
||||
MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) {
|
||||
bt_dev_info(hdev, "Mediatek coredump end");
|
||||
hci_devcd_complete(hdev);
|
||||
}
|
||||
if (complete) {
|
||||
bt_dev_info(hdev, "Mediatek coredump end");
|
||||
hci_devcd_complete(hdev);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1520,9 +1520,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
|
||||
struct slave *slave;
|
||||
|
||||
mask = features;
|
||||
|
||||
features &= ~NETIF_F_ONE_FOR_ALL;
|
||||
features |= NETIF_F_ALL_FOR_ALL;
|
||||
features = netdev_base_features(features);
|
||||
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
features = netdev_increment_features(features,
|
||||
@ -1536,6 +1534,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
|
||||
|
||||
#define BOND_VLAN_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
|
||||
NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | \
|
||||
NETIF_F_GSO_ENCAP_ALL | \
|
||||
NETIF_F_HIGHDMA | NETIF_F_LRO)
|
||||
|
||||
#define BOND_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
|
||||
@ -1565,8 +1564,9 @@ static void bond_compute_features(struct bonding *bond)
|
||||
|
||||
if (!bond_has_slaves(bond))
|
||||
goto done;
|
||||
vlan_features &= NETIF_F_ALL_FOR_ALL;
|
||||
mpls_features &= NETIF_F_ALL_FOR_ALL;
|
||||
|
||||
vlan_features = netdev_base_features(vlan_features);
|
||||
mpls_features = netdev_base_features(mpls_features);
|
||||
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
vlan_features = netdev_increment_features(vlan_features,
|
||||
|
@ -1100,10 +1100,9 @@ static const struct regmap_range ksz9896_valid_regs[] = {
|
||||
regmap_reg_range(0x1030, 0x1030),
|
||||
regmap_reg_range(0x1100, 0x1115),
|
||||
regmap_reg_range(0x111a, 0x111f),
|
||||
regmap_reg_range(0x1122, 0x1127),
|
||||
regmap_reg_range(0x112a, 0x112b),
|
||||
regmap_reg_range(0x1136, 0x1139),
|
||||
regmap_reg_range(0x113e, 0x113f),
|
||||
regmap_reg_range(0x1120, 0x112b),
|
||||
regmap_reg_range(0x1134, 0x113b),
|
||||
regmap_reg_range(0x113c, 0x113f),
|
||||
regmap_reg_range(0x1400, 0x1401),
|
||||
regmap_reg_range(0x1403, 0x1403),
|
||||
regmap_reg_range(0x1410, 0x1417),
|
||||
@ -1130,10 +1129,9 @@ static const struct regmap_range ksz9896_valid_regs[] = {
|
||||
regmap_reg_range(0x2030, 0x2030),
|
||||
regmap_reg_range(0x2100, 0x2115),
|
||||
regmap_reg_range(0x211a, 0x211f),
|
||||
regmap_reg_range(0x2122, 0x2127),
|
||||
regmap_reg_range(0x212a, 0x212b),
|
||||
regmap_reg_range(0x2136, 0x2139),
|
||||
regmap_reg_range(0x213e, 0x213f),
|
||||
regmap_reg_range(0x2120, 0x212b),
|
||||
regmap_reg_range(0x2134, 0x213b),
|
||||
regmap_reg_range(0x213c, 0x213f),
|
||||
regmap_reg_range(0x2400, 0x2401),
|
||||
regmap_reg_range(0x2403, 0x2403),
|
||||
regmap_reg_range(0x2410, 0x2417),
|
||||
@ -1160,10 +1158,9 @@ static const struct regmap_range ksz9896_valid_regs[] = {
|
||||
regmap_reg_range(0x3030, 0x3030),
|
||||
regmap_reg_range(0x3100, 0x3115),
|
||||
regmap_reg_range(0x311a, 0x311f),
|
||||
regmap_reg_range(0x3122, 0x3127),
|
||||
regmap_reg_range(0x312a, 0x312b),
|
||||
regmap_reg_range(0x3136, 0x3139),
|
||||
regmap_reg_range(0x313e, 0x313f),
|
||||
regmap_reg_range(0x3120, 0x312b),
|
||||
regmap_reg_range(0x3134, 0x313b),
|
||||
regmap_reg_range(0x313c, 0x313f),
|
||||
regmap_reg_range(0x3400, 0x3401),
|
||||
regmap_reg_range(0x3403, 0x3403),
|
||||
regmap_reg_range(0x3410, 0x3417),
|
||||
@ -1190,10 +1187,9 @@ static const struct regmap_range ksz9896_valid_regs[] = {
|
||||
regmap_reg_range(0x4030, 0x4030),
|
||||
regmap_reg_range(0x4100, 0x4115),
|
||||
regmap_reg_range(0x411a, 0x411f),
|
||||
regmap_reg_range(0x4122, 0x4127),
|
||||
regmap_reg_range(0x412a, 0x412b),
|
||||
regmap_reg_range(0x4136, 0x4139),
|
||||
regmap_reg_range(0x413e, 0x413f),
|
||||
regmap_reg_range(0x4120, 0x412b),
|
||||
regmap_reg_range(0x4134, 0x413b),
|
||||
regmap_reg_range(0x413c, 0x413f),
|
||||
regmap_reg_range(0x4400, 0x4401),
|
||||
regmap_reg_range(0x4403, 0x4403),
|
||||
regmap_reg_range(0x4410, 0x4417),
|
||||
@ -1220,10 +1216,9 @@ static const struct regmap_range ksz9896_valid_regs[] = {
|
||||
regmap_reg_range(0x5030, 0x5030),
|
||||
regmap_reg_range(0x5100, 0x5115),
|
||||
regmap_reg_range(0x511a, 0x511f),
|
||||
regmap_reg_range(0x5122, 0x5127),
|
||||
regmap_reg_range(0x512a, 0x512b),
|
||||
regmap_reg_range(0x5136, 0x5139),
|
||||
regmap_reg_range(0x513e, 0x513f),
|
||||
regmap_reg_range(0x5120, 0x512b),
|
||||
regmap_reg_range(0x5134, 0x513b),
|
||||
regmap_reg_range(0x513c, 0x513f),
|
||||
regmap_reg_range(0x5400, 0x5401),
|
||||
regmap_reg_range(0x5403, 0x5403),
|
||||
regmap_reg_range(0x5410, 0x5417),
|
||||
@ -1250,10 +1245,9 @@ static const struct regmap_range ksz9896_valid_regs[] = {
|
||||
regmap_reg_range(0x6030, 0x6030),
|
||||
regmap_reg_range(0x6100, 0x6115),
|
||||
regmap_reg_range(0x611a, 0x611f),
|
||||
regmap_reg_range(0x6122, 0x6127),
|
||||
regmap_reg_range(0x612a, 0x612b),
|
||||
regmap_reg_range(0x6136, 0x6139),
|
||||
regmap_reg_range(0x613e, 0x613f),
|
||||
regmap_reg_range(0x6120, 0x612b),
|
||||
regmap_reg_range(0x6134, 0x613b),
|
||||
regmap_reg_range(0x613c, 0x613f),
|
||||
regmap_reg_range(0x6300, 0x6301),
|
||||
regmap_reg_range(0x6400, 0x6401),
|
||||
regmap_reg_range(0x6403, 0x6403),
|
||||
|
@ -24,7 +24,7 @@
|
||||
#define VSC9959_NUM_PORTS 6
|
||||
|
||||
#define VSC9959_TAS_GCL_ENTRY_MAX 63
|
||||
#define VSC9959_TAS_MIN_GATE_LEN_NS 33
|
||||
#define VSC9959_TAS_MIN_GATE_LEN_NS 35
|
||||
#define VSC9959_VCAP_POLICER_BASE 63
|
||||
#define VSC9959_VCAP_POLICER_MAX 383
|
||||
#define VSC9959_SWITCH_PCI_BAR 4
|
||||
@ -1056,11 +1056,15 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
|
||||
mdiobus_free(felix->imdio);
|
||||
}
|
||||
|
||||
/* The switch considers any frame (regardless of size) as eligible for
|
||||
* transmission if the traffic class gate is open for at least 33 ns.
|
||||
/* The switch considers any frame (regardless of size) as eligible
|
||||
* for transmission if the traffic class gate is open for at least
|
||||
* VSC9959_TAS_MIN_GATE_LEN_NS.
|
||||
*
|
||||
* Overruns are prevented by cropping an interval at the end of the gate time
|
||||
* slot for which egress scheduling is blocked, but we need to still keep 33 ns
|
||||
* available for one packet to be transmitted, otherwise the port tc will hang.
|
||||
* slot for which egress scheduling is blocked, but we need to still keep
|
||||
* VSC9959_TAS_MIN_GATE_LEN_NS available for one packet to be transmitted,
|
||||
* otherwise the port tc will hang.
|
||||
*
|
||||
* This function returns the size of a gate interval that remains available for
|
||||
* setting the guard band, after reserving the space for one egress frame.
|
||||
*/
|
||||
@ -1303,7 +1307,8 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
|
||||
* per-tc static guard band lengths, so it reduces the
|
||||
* useful gate interval length. Therefore, be careful
|
||||
* to calculate a guard band (and therefore max_sdu)
|
||||
* that still leaves 33 ns available in the time slot.
|
||||
* that still leaves VSC9959_TAS_MIN_GATE_LEN_NS
|
||||
* available in the time slot.
|
||||
*/
|
||||
max_sdu = div_u64(remaining_gate_len_ps, picos_per_byte);
|
||||
/* A TC gate may be completely closed, which is a
|
||||
|
@ -1531,7 +1531,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
|
||||
if (TPA_START_IS_IPV6(tpa_start1))
|
||||
tpa_info->gso_type = SKB_GSO_TCPV6;
|
||||
/* RSS profiles 1 and 3 with extract code 0 for inner 4-tuple */
|
||||
else if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP &&
|
||||
else if (!BNXT_CHIP_P4_PLUS(bp) &&
|
||||
TPA_START_HASH_TYPE(tpa_start) == 3)
|
||||
tpa_info->gso_type = SKB_GSO_TCPV6;
|
||||
tpa_info->rss_hash =
|
||||
@ -2226,15 +2226,13 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
|
||||
if (cmp_type == CMP_TYPE_RX_L2_V3_CMP) {
|
||||
type = bnxt_rss_ext_op(bp, rxcmp);
|
||||
} else {
|
||||
u32 hash_type = RX_CMP_HASH_TYPE(rxcmp);
|
||||
u32 itypes = RX_CMP_ITYPES(rxcmp);
|
||||
|
||||
/* RSS profiles 1 and 3 with extract code 0 for inner
|
||||
* 4-tuple
|
||||
*/
|
||||
if (hash_type != 1 && hash_type != 3)
|
||||
type = PKT_HASH_TYPE_L3;
|
||||
else
|
||||
if (itypes == RX_CMP_FLAGS_ITYPE_TCP ||
|
||||
itypes == RX_CMP_FLAGS_ITYPE_UDP)
|
||||
type = PKT_HASH_TYPE_L4;
|
||||
else
|
||||
type = PKT_HASH_TYPE_L3;
|
||||
}
|
||||
skb_set_hash(skb, le32_to_cpu(rxcmp->rx_cmp_rss_hash), type);
|
||||
}
|
||||
@ -8367,7 +8365,7 @@ static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp, int ctx_max)
|
||||
struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
|
||||
int n = 1;
|
||||
|
||||
if (!ctxm->max_entries)
|
||||
if (!ctxm->max_entries || ctxm->pg_info)
|
||||
continue;
|
||||
|
||||
if (ctxm->instance_bmap)
|
||||
@ -8971,8 +8969,8 @@ static int bnxt_backing_store_cfg_v2(struct bnxt *bp, u32 ena)
|
||||
continue;
|
||||
}
|
||||
bnxt_bs_trace_init(bp, ctxm);
|
||||
last_type = type;
|
||||
}
|
||||
last_type = type;
|
||||
}
|
||||
|
||||
if (last_type == BNXT_CTX_INV) {
|
||||
|
@ -267,6 +267,9 @@ struct rx_cmp {
|
||||
(((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_RSS_HASH_TYPE) >>\
|
||||
RX_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK)
|
||||
|
||||
#define RX_CMP_ITYPES(rxcmp) \
|
||||
(le32_to_cpu((rxcmp)->rx_cmp_len_flags_type) & RX_CMP_FLAGS_ITYPES_MASK)
|
||||
|
||||
#define RX_CMP_V3_HASH_TYPE_LEGACY(rxcmp) \
|
||||
((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_V3_RSS_EXT_OP_LEGACY) >>\
|
||||
RX_CMP_V3_RSS_EXT_OP_LEGACY_SHIFT)
|
||||
@ -378,7 +381,7 @@ struct rx_agg_cmp {
|
||||
u32 rx_agg_cmp_opaque;
|
||||
__le32 rx_agg_cmp_v;
|
||||
#define RX_AGG_CMP_V (1 << 0)
|
||||
#define RX_AGG_CMP_AGG_ID (0xffff << 16)
|
||||
#define RX_AGG_CMP_AGG_ID (0x0fff << 16)
|
||||
#define RX_AGG_CMP_AGG_ID_SHIFT 16
|
||||
__le32 rx_agg_cmp_unused;
|
||||
};
|
||||
@ -416,7 +419,7 @@ struct rx_tpa_start_cmp {
|
||||
#define RX_TPA_START_CMP_V3_RSS_HASH_TYPE_SHIFT 7
|
||||
#define RX_TPA_START_CMP_AGG_ID (0x7f << 25)
|
||||
#define RX_TPA_START_CMP_AGG_ID_SHIFT 25
|
||||
#define RX_TPA_START_CMP_AGG_ID_P5 (0xffff << 16)
|
||||
#define RX_TPA_START_CMP_AGG_ID_P5 (0x0fff << 16)
|
||||
#define RX_TPA_START_CMP_AGG_ID_SHIFT_P5 16
|
||||
#define RX_TPA_START_CMP_METADATA1 (0xf << 28)
|
||||
#define RX_TPA_START_CMP_METADATA1_SHIFT 28
|
||||
@ -540,7 +543,7 @@ struct rx_tpa_end_cmp {
|
||||
#define RX_TPA_END_CMP_PAYLOAD_OFFSET_SHIFT 16
|
||||
#define RX_TPA_END_CMP_AGG_ID (0x7f << 25)
|
||||
#define RX_TPA_END_CMP_AGG_ID_SHIFT 25
|
||||
#define RX_TPA_END_CMP_AGG_ID_P5 (0xffff << 16)
|
||||
#define RX_TPA_END_CMP_AGG_ID_P5 (0x0fff << 16)
|
||||
#define RX_TPA_END_CMP_AGG_ID_SHIFT_P5 16
|
||||
|
||||
__le32 rx_tpa_end_cmp_tsdelta;
|
||||
|
@ -2076,7 +2076,7 @@ void t4_idma_monitor(struct adapter *adapter,
|
||||
struct sge_idma_monitor_state *idma,
|
||||
int hz, int ticks);
|
||||
int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf,
|
||||
unsigned int naddr, u8 *addr);
|
||||
u8 start, unsigned int naddr, u8 *addr);
|
||||
void t4_tp_pio_read(struct adapter *adap, u32 *buff, u32 nregs,
|
||||
u32 start_index, bool sleep_ok);
|
||||
void t4_tp_tm_pio_read(struct adapter *adap, u32 *buff, u32 nregs,
|
||||
|
@ -3234,7 +3234,7 @@ static int cxgb4_mgmt_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
|
||||
|
||||
dev_info(pi->adapter->pdev_dev,
|
||||
"Setting MAC %pM on VF %d\n", mac, vf);
|
||||
ret = t4_set_vf_mac_acl(adap, vf + 1, 1, mac);
|
||||
ret = t4_set_vf_mac_acl(adap, vf + 1, pi->lport, 1, mac);
|
||||
if (!ret)
|
||||
ether_addr_copy(adap->vfinfo[vf].vf_mac_addr, mac);
|
||||
return ret;
|
||||
|
@ -10215,11 +10215,12 @@ int t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size)
|
||||
* t4_set_vf_mac_acl - Set MAC address for the specified VF
|
||||
* @adapter: The adapter
|
||||
* @vf: one of the VFs instantiated by the specified PF
|
||||
* @start: The start port id associated with specified VF
|
||||
* @naddr: the number of MAC addresses
|
||||
* @addr: the MAC address(es) to be set to the specified VF
|
||||
*/
|
||||
int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf,
|
||||
unsigned int naddr, u8 *addr)
|
||||
u8 start, unsigned int naddr, u8 *addr)
|
||||
{
|
||||
struct fw_acl_mac_cmd cmd;
|
||||
|
||||
@ -10234,7 +10235,7 @@ int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf,
|
||||
cmd.en_to_len16 = cpu_to_be32((unsigned int)FW_LEN16(cmd));
|
||||
cmd.nmac = naddr;
|
||||
|
||||
switch (adapter->pf) {
|
||||
switch (start) {
|
||||
case 3:
|
||||
memcpy(cmd.macaddr3, addr, sizeof(cmd.macaddr3));
|
||||
break;
|
||||
|
@ -1452,23 +1452,21 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
|
||||
* hence modify pcifunc accordingly.
|
||||
*/
|
||||
|
||||
/* AF installing for a PF/VF */
|
||||
if (!req->hdr.pcifunc)
|
||||
if (!req->hdr.pcifunc) {
|
||||
/* AF installing for a PF/VF */
|
||||
target = req->vf;
|
||||
|
||||
/* PF installing for its VF */
|
||||
if (!from_vf && req->vf && !from_rep_dev) {
|
||||
} else if (!from_vf && req->vf && !from_rep_dev) {
|
||||
/* PF installing for its VF */
|
||||
target = (req->hdr.pcifunc & ~RVU_PFVF_FUNC_MASK) | req->vf;
|
||||
pf_set_vfs_mac = req->default_rule &&
|
||||
(req->features & BIT_ULL(NPC_DMAC));
|
||||
}
|
||||
|
||||
/* Representor device installing for a representee */
|
||||
if (from_rep_dev && req->vf)
|
||||
} else if (from_rep_dev && req->vf) {
|
||||
/* Representor device installing for a representee */
|
||||
target = req->vf;
|
||||
else
|
||||
} else {
|
||||
/* msg received from PF/VF */
|
||||
target = req->hdr.pcifunc;
|
||||
}
|
||||
|
||||
/* ignore chan_mask in case pf func is not AF, revisit later */
|
||||
if (!is_pffunc_af(req->hdr.pcifunc))
|
||||
|
@ -297,7 +297,9 @@ dr_domain_add_vport_cap(struct mlx5dr_domain *dmn, u16 vport)
|
||||
if (ret) {
|
||||
mlx5dr_dbg(dmn, "Couldn't insert new vport into xarray (%d)\n", ret);
|
||||
kvfree(vport_caps);
|
||||
return ERR_PTR(ret);
|
||||
if (ret == -EBUSY)
|
||||
return ERR_PTR(-EBUSY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vport_caps;
|
||||
|
@ -59,7 +59,6 @@ config LAN743X
|
||||
|
||||
source "drivers/net/ethernet/microchip/lan865x/Kconfig"
|
||||
source "drivers/net/ethernet/microchip/lan966x/Kconfig"
|
||||
source "drivers/net/ethernet/microchip/lan969x/Kconfig"
|
||||
source "drivers/net/ethernet/microchip/sparx5/Kconfig"
|
||||
source "drivers/net/ethernet/microchip/vcap/Kconfig"
|
||||
source "drivers/net/ethernet/microchip/fdma/Kconfig"
|
||||
|
@ -11,7 +11,6 @@ lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
|
||||
|
||||
obj-$(CONFIG_LAN865X) += lan865x/
|
||||
obj-$(CONFIG_LAN966X_SWITCH) += lan966x/
|
||||
obj-$(CONFIG_LAN969X_SWITCH) += lan969x/
|
||||
obj-$(CONFIG_SPARX5_SWITCH) += sparx5/
|
||||
obj-$(CONFIG_VCAP) += vcap/
|
||||
obj-$(CONFIG_FDMA) += fdma/
|
||||
|
@ -1,5 +0,0 @@
|
||||
config LAN969X_SWITCH
|
||||
bool "Lan969x switch driver"
|
||||
depends on SPARX5_SWITCH
|
||||
help
|
||||
This driver supports the lan969x family of network switch devices.
|
@ -1,13 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Makefile for the Microchip lan969x network device drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SPARX5_SWITCH) += lan969x-switch.o
|
||||
|
||||
lan969x-switch-y := lan969x_regs.o lan969x.o lan969x_calendar.o \
|
||||
lan969x_vcap_ag_api.o lan969x_vcap_impl.o
|
||||
|
||||
# Provide include files
|
||||
ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/fdma
|
||||
ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/vcap
|
@ -24,3 +24,9 @@ config SPARX5_DCB
|
||||
DSCP and PCP.
|
||||
|
||||
If unsure, set to Y.
|
||||
|
||||
config LAN969X_SWITCH
|
||||
bool "Lan969x switch driver"
|
||||
depends on SPARX5_SWITCH
|
||||
help
|
||||
This driver supports the lan969x family of network switch devices.
|
||||
|
@ -16,6 +16,12 @@ sparx5-switch-y := sparx5_main.o sparx5_packet.o \
|
||||
sparx5-switch-$(CONFIG_SPARX5_DCB) += sparx5_dcb.o
|
||||
sparx5-switch-$(CONFIG_DEBUG_FS) += sparx5_vcap_debugfs.o
|
||||
|
||||
sparx5-switch-$(CONFIG_LAN969X_SWITCH) += lan969x/lan969x_regs.o \
|
||||
lan969x/lan969x.o \
|
||||
lan969x/lan969x_calendar.o \
|
||||
lan969x/lan969x_vcap_ag_api.o \
|
||||
lan969x/lan969x_vcap_impl.o
|
||||
|
||||
# Provide include files
|
||||
ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/vcap
|
||||
ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/fdma
|
||||
|
@ -273,9 +273,9 @@ static irqreturn_t lan969x_ptp_irq_handler(int irq, void *args)
|
||||
if (WARN_ON(!skb_match))
|
||||
continue;
|
||||
|
||||
spin_lock(&sparx5->ptp_ts_id_lock);
|
||||
spin_lock_irqsave(&sparx5->ptp_ts_id_lock, flags);
|
||||
sparx5->ptp_skbs--;
|
||||
spin_unlock(&sparx5->ptp_ts_id_lock);
|
||||
spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags);
|
||||
|
||||
/* Get the h/w timestamp */
|
||||
sparx5_get_hwtimestamp(sparx5, &ts, delay);
|
||||
@ -346,8 +346,3 @@ const struct sparx5_match_data lan969x_desc = {
|
||||
.consts = &lan969x_consts,
|
||||
.ops = &lan969x_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(lan969x_desc);
|
||||
|
||||
MODULE_DESCRIPTION("Microchip lan969x switch driver");
|
||||
MODULE_AUTHOR("Daniel Machon <daniel.machon@microchip.com>");
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
@ -98,7 +98,6 @@ u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed)
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sparx5_cal_speed_to_value);
|
||||
|
||||
static u32 sparx5_bandwidth_to_calendar(u32 bw)
|
||||
{
|
||||
@ -150,7 +149,6 @@ enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5, u32 portno)
|
||||
return SPX5_CAL_SPEED_NONE;
|
||||
return sparx5_bandwidth_to_calendar(port->conf.bandwidth);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sparx5_get_port_cal_speed);
|
||||
|
||||
/* Auto configure the QSYS calendar based on port configuration */
|
||||
int sparx5_config_auto_calendar(struct sparx5 *sparx5)
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "../lan969x/lan969x.h" /* for lan969x match data */
|
||||
#include "lan969x/lan969x.h" /* for lan969x match data */
|
||||
|
||||
#include "sparx5_main_regs.h"
|
||||
#include "sparx5_main.h"
|
||||
@ -780,12 +780,11 @@ static int sparx5_start(struct sparx5 *sparx5)
|
||||
err = -ENXIO;
|
||||
if (sparx5->fdma_irq >= 0 && is_sparx5(sparx5)) {
|
||||
if (GCB_CHIP_ID_REV_ID_GET(sparx5->chip_id) > 0)
|
||||
err = devm_request_threaded_irq(sparx5->dev,
|
||||
sparx5->fdma_irq,
|
||||
NULL,
|
||||
sparx5_fdma_handler,
|
||||
IRQF_ONESHOT,
|
||||
"sparx5-fdma", sparx5);
|
||||
err = devm_request_irq(sparx5->dev,
|
||||
sparx5->fdma_irq,
|
||||
sparx5_fdma_handler,
|
||||
0,
|
||||
"sparx5-fdma", sparx5);
|
||||
if (!err)
|
||||
err = sparx5_fdma_start(sparx5);
|
||||
if (err)
|
||||
@ -1093,7 +1092,7 @@ static const struct sparx5_match_data sparx5_desc = {
|
||||
|
||||
static const struct of_device_id mchp_sparx5_match[] = {
|
||||
{ .compatible = "microchip,sparx5-switch", .data = &sparx5_desc },
|
||||
#if IS_ENABLED(CONFIG_LAN969X_SWITCH)
|
||||
#ifdef CONFIG_LAN969X_SWITCH
|
||||
{ .compatible = "microchip,lan9691-switch", .data = &lan969x_desc },
|
||||
#endif
|
||||
{ }
|
||||
|
@ -12,7 +12,6 @@
|
||||
#define SPX5_MIRROR_DISABLED 0
|
||||
#define SPX5_MIRROR_EGRESS 1
|
||||
#define SPX5_MIRROR_INGRESS 2
|
||||
#define SPX5_MIRROR_MONITOR_PORT_DEFAULT 65
|
||||
#define SPX5_QFWD_MP_OFFSET 9 /* Mirror port offset in the QFWD register */
|
||||
|
||||
/* Convert from bool ingress/egress to mirror direction */
|
||||
@ -200,7 +199,7 @@ void sparx5_mirror_del(struct sparx5_mall_entry *entry)
|
||||
|
||||
sparx5_mirror_monitor_set(sparx5,
|
||||
mirror_idx,
|
||||
SPX5_MIRROR_MONITOR_PORT_DEFAULT);
|
||||
sparx5->data->consts->n_ports);
|
||||
}
|
||||
|
||||
void sparx5_mirror_stats(struct sparx5_mall_entry *entry,
|
||||
|
@ -1151,7 +1151,7 @@ int sparx5_port_init(struct sparx5 *sparx5,
|
||||
spx5_inst_rmw(DEV10G_MAC_MAXLEN_CFG_MAX_LEN_SET(ETH_MAXLEN),
|
||||
DEV10G_MAC_MAXLEN_CFG_MAX_LEN,
|
||||
devinst,
|
||||
DEV10G_MAC_ENA_CFG(0));
|
||||
DEV10G_MAC_MAXLEN_CFG(0));
|
||||
|
||||
/* Handle Signal Detect in 10G PCS */
|
||||
spx5_inst_wr(PCS10G_BR_PCS_SD_CFG_SD_POL_SET(sd_pol) |
|
||||
|
@ -303,7 +303,6 @@ void sparx5_get_hwtimestamp(struct sparx5 *sparx5,
|
||||
|
||||
spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sparx5_get_hwtimestamp);
|
||||
|
||||
irqreturn_t sparx5_ptp_irq_handler(int irq, void *args)
|
||||
{
|
||||
|
@ -1318,7 +1318,7 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
|
||||
GFP_KERNEL);
|
||||
if (!gc->irq_contexts) {
|
||||
err = -ENOMEM;
|
||||
goto free_irq_vector;
|
||||
goto free_irq_array;
|
||||
}
|
||||
|
||||
for (i = 0; i < nvec; i++) {
|
||||
@ -1375,6 +1375,7 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
|
||||
gc->max_num_msix = nvec;
|
||||
gc->num_msix_usable = nvec;
|
||||
cpus_read_unlock();
|
||||
kfree(irqs);
|
||||
return 0;
|
||||
|
||||
free_irq:
|
||||
@ -1387,8 +1388,9 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
|
||||
}
|
||||
|
||||
kfree(gc->irq_contexts);
|
||||
kfree(irqs);
|
||||
gc->irq_contexts = NULL;
|
||||
free_irq_array:
|
||||
kfree(irqs);
|
||||
free_irq_vector:
|
||||
cpus_read_unlock();
|
||||
pci_free_irq_vectors(pdev);
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include <soc/mscc/ocelot.h>
|
||||
#include "ocelot.h"
|
||||
|
||||
#define OCELOT_PTP_TX_TSTAMP_TIMEOUT (5 * HZ)
|
||||
|
||||
int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts)
|
||||
{
|
||||
struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
|
||||
@ -495,6 +497,28 @@ static int ocelot_traps_to_ptp_rx_filter(unsigned int proto)
|
||||
return HWTSTAMP_FILTER_NONE;
|
||||
}
|
||||
|
||||
static int ocelot_ptp_tx_type_to_cmd(int tx_type, int *ptp_cmd)
|
||||
{
|
||||
switch (tx_type) {
|
||||
case HWTSTAMP_TX_ON:
|
||||
*ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
|
||||
break;
|
||||
case HWTSTAMP_TX_ONESTEP_SYNC:
|
||||
/* IFH_REW_OP_ONE_STEP_PTP updates the correctionField,
|
||||
* what we need to update is the originTimestamp.
|
||||
*/
|
||||
*ptp_cmd = IFH_REW_OP_ORIGIN_PTP;
|
||||
break;
|
||||
case HWTSTAMP_TX_OFF:
|
||||
*ptp_cmd = 0;
|
||||
break;
|
||||
default:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr)
|
||||
{
|
||||
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
||||
@ -521,30 +545,19 @@ EXPORT_SYMBOL(ocelot_hwstamp_get);
|
||||
int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
|
||||
{
|
||||
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
||||
int ptp_cmd, old_ptp_cmd = ocelot_port->ptp_cmd;
|
||||
bool l2 = false, l4 = false;
|
||||
struct hwtstamp_config cfg;
|
||||
bool old_l2, old_l4;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
|
||||
return -EFAULT;
|
||||
|
||||
/* Tx type sanity check */
|
||||
switch (cfg.tx_type) {
|
||||
case HWTSTAMP_TX_ON:
|
||||
ocelot_port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
|
||||
break;
|
||||
case HWTSTAMP_TX_ONESTEP_SYNC:
|
||||
/* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we
|
||||
* need to update the origin time.
|
||||
*/
|
||||
ocelot_port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP;
|
||||
break;
|
||||
case HWTSTAMP_TX_OFF:
|
||||
ocelot_port->ptp_cmd = 0;
|
||||
break;
|
||||
default:
|
||||
return -ERANGE;
|
||||
}
|
||||
err = ocelot_ptp_tx_type_to_cmd(cfg.tx_type, &ptp_cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (cfg.rx_filter) {
|
||||
case HWTSTAMP_FILTER_NONE:
|
||||
@ -569,13 +582,27 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
old_l2 = ocelot_port->trap_proto & OCELOT_PROTO_PTP_L2;
|
||||
old_l4 = ocelot_port->trap_proto & OCELOT_PROTO_PTP_L4;
|
||||
|
||||
err = ocelot_setup_ptp_traps(ocelot, port, l2, l4);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ocelot_port->ptp_cmd = ptp_cmd;
|
||||
|
||||
cfg.rx_filter = ocelot_traps_to_ptp_rx_filter(ocelot_port->trap_proto);
|
||||
|
||||
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
|
||||
if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg))) {
|
||||
err = -EFAULT;
|
||||
goto out_restore_ptp_traps;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_restore_ptp_traps:
|
||||
ocelot_setup_ptp_traps(ocelot, port, old_l2, old_l4);
|
||||
ocelot_port->ptp_cmd = old_ptp_cmd;
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(ocelot_hwstamp_set);
|
||||
|
||||
@ -603,34 +630,87 @@ int ocelot_get_ts_info(struct ocelot *ocelot, int port,
|
||||
}
|
||||
EXPORT_SYMBOL(ocelot_get_ts_info);
|
||||
|
||||
static int ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port,
|
||||
static struct sk_buff *ocelot_port_dequeue_ptp_tx_skb(struct ocelot *ocelot,
|
||||
int port, u8 ts_id,
|
||||
u32 seqid)
|
||||
{
|
||||
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
||||
struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
|
||||
struct ptp_header *hdr;
|
||||
|
||||
spin_lock(&ocelot->ts_id_lock);
|
||||
|
||||
skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) {
|
||||
if (OCELOT_SKB_CB(skb)->ts_id != ts_id)
|
||||
continue;
|
||||
|
||||
/* Check that the timestamp ID is for the expected PTP
|
||||
* sequenceId. We don't have to test ptp_parse_header() against
|
||||
* NULL, because we've pre-validated the packet's ptp_class.
|
||||
*/
|
||||
hdr = ptp_parse_header(skb, OCELOT_SKB_CB(skb)->ptp_class);
|
||||
if (seqid != ntohs(hdr->sequence_id))
|
||||
continue;
|
||||
|
||||
__skb_unlink(skb, &ocelot_port->tx_skbs);
|
||||
ocelot->ptp_skbs_in_flight--;
|
||||
skb_match = skb;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&ocelot->ts_id_lock);
|
||||
|
||||
return skb_match;
|
||||
}
|
||||
|
||||
static int ocelot_port_queue_ptp_tx_skb(struct ocelot *ocelot, int port,
|
||||
struct sk_buff *clone)
|
||||
{
|
||||
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
||||
unsigned long flags;
|
||||
DECLARE_BITMAP(ts_id_in_flight, OCELOT_MAX_PTP_ID);
|
||||
struct sk_buff *skb, *skb_tmp;
|
||||
unsigned long n;
|
||||
|
||||
spin_lock_irqsave(&ocelot->ts_id_lock, flags);
|
||||
spin_lock(&ocelot->ts_id_lock);
|
||||
|
||||
if (ocelot_port->ptp_skbs_in_flight == OCELOT_MAX_PTP_ID ||
|
||||
ocelot->ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE) {
|
||||
spin_unlock_irqrestore(&ocelot->ts_id_lock, flags);
|
||||
/* To get a better chance of acquiring a timestamp ID, first flush the
|
||||
* stale packets still waiting in the TX timestamping queue. They are
|
||||
* probably lost.
|
||||
*/
|
||||
skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) {
|
||||
if (time_before(OCELOT_SKB_CB(skb)->ptp_tx_time +
|
||||
OCELOT_PTP_TX_TSTAMP_TIMEOUT, jiffies)) {
|
||||
dev_warn_ratelimited(ocelot->dev,
|
||||
"port %d invalidating stale timestamp ID %u which seems lost\n",
|
||||
port, OCELOT_SKB_CB(skb)->ts_id);
|
||||
__skb_unlink(skb, &ocelot_port->tx_skbs);
|
||||
kfree_skb(skb);
|
||||
ocelot->ptp_skbs_in_flight--;
|
||||
} else {
|
||||
__set_bit(OCELOT_SKB_CB(skb)->ts_id, ts_id_in_flight);
|
||||
}
|
||||
}
|
||||
|
||||
if (ocelot->ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE) {
|
||||
spin_unlock(&ocelot->ts_id_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
|
||||
/* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */
|
||||
OCELOT_SKB_CB(clone)->ts_id = ocelot_port->ts_id;
|
||||
n = find_first_zero_bit(ts_id_in_flight, OCELOT_MAX_PTP_ID);
|
||||
if (n == OCELOT_MAX_PTP_ID) {
|
||||
spin_unlock(&ocelot->ts_id_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ocelot_port->ts_id++;
|
||||
if (ocelot_port->ts_id == OCELOT_MAX_PTP_ID)
|
||||
ocelot_port->ts_id = 0;
|
||||
|
||||
ocelot_port->ptp_skbs_in_flight++;
|
||||
/* Found an available timestamp ID, use it */
|
||||
OCELOT_SKB_CB(clone)->ts_id = n;
|
||||
OCELOT_SKB_CB(clone)->ptp_tx_time = jiffies;
|
||||
ocelot->ptp_skbs_in_flight++;
|
||||
__skb_queue_tail(&ocelot_port->tx_skbs, clone);
|
||||
|
||||
skb_queue_tail(&ocelot_port->tx_skbs, clone);
|
||||
spin_unlock(&ocelot->ts_id_lock);
|
||||
|
||||
spin_unlock_irqrestore(&ocelot->ts_id_lock, flags);
|
||||
dev_dbg_ratelimited(ocelot->dev, "port %d timestamp id %lu\n", port, n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -687,10 +767,14 @@ int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port,
|
||||
if (!(*clone))
|
||||
return -ENOMEM;
|
||||
|
||||
err = ocelot_port_add_txtstamp_skb(ocelot, port, *clone);
|
||||
if (err)
|
||||
/* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */
|
||||
err = ocelot_port_queue_ptp_tx_skb(ocelot, port, *clone);
|
||||
if (err) {
|
||||
kfree_skb(*clone);
|
||||
return err;
|
||||
}
|
||||
|
||||
skb_shinfo(*clone)->tx_flags |= SKBTX_IN_PROGRESS;
|
||||
OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd;
|
||||
OCELOT_SKB_CB(*clone)->ptp_class = ptp_class;
|
||||
}
|
||||
@ -726,28 +810,15 @@ static void ocelot_get_hwtimestamp(struct ocelot *ocelot,
|
||||
spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
|
||||
}
|
||||
|
||||
static bool ocelot_validate_ptp_skb(struct sk_buff *clone, u16 seqid)
|
||||
{
|
||||
struct ptp_header *hdr;
|
||||
|
||||
hdr = ptp_parse_header(clone, OCELOT_SKB_CB(clone)->ptp_class);
|
||||
if (WARN_ON(!hdr))
|
||||
return false;
|
||||
|
||||
return seqid == ntohs(hdr->sequence_id);
|
||||
}
|
||||
|
||||
void ocelot_get_txtstamp(struct ocelot *ocelot)
|
||||
{
|
||||
int budget = OCELOT_PTP_QUEUE_SZ;
|
||||
|
||||
while (budget--) {
|
||||
struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
|
||||
struct skb_shared_hwtstamps shhwtstamps;
|
||||
u32 val, id, seqid, txport;
|
||||
struct ocelot_port *port;
|
||||
struct sk_buff *skb_match;
|
||||
struct timespec64 ts;
|
||||
unsigned long flags;
|
||||
|
||||
val = ocelot_read(ocelot, SYS_PTP_STATUS);
|
||||
|
||||
@ -762,36 +833,14 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
|
||||
txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val);
|
||||
seqid = SYS_PTP_STATUS_PTP_MESS_SEQ_ID(val);
|
||||
|
||||
port = ocelot->ports[txport];
|
||||
|
||||
spin_lock(&ocelot->ts_id_lock);
|
||||
port->ptp_skbs_in_flight--;
|
||||
ocelot->ptp_skbs_in_flight--;
|
||||
spin_unlock(&ocelot->ts_id_lock);
|
||||
|
||||
/* Retrieve its associated skb */
|
||||
try_again:
|
||||
spin_lock_irqsave(&port->tx_skbs.lock, flags);
|
||||
|
||||
skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) {
|
||||
if (OCELOT_SKB_CB(skb)->ts_id != id)
|
||||
continue;
|
||||
__skb_unlink(skb, &port->tx_skbs);
|
||||
skb_match = skb;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
|
||||
|
||||
if (WARN_ON(!skb_match))
|
||||
continue;
|
||||
|
||||
if (!ocelot_validate_ptp_skb(skb_match, seqid)) {
|
||||
dev_err_ratelimited(ocelot->dev,
|
||||
"port %d received stale TX timestamp for seqid %d, discarding\n",
|
||||
txport, seqid);
|
||||
dev_kfree_skb_any(skb);
|
||||
goto try_again;
|
||||
skb_match = ocelot_port_dequeue_ptp_tx_skb(ocelot, txport, id,
|
||||
seqid);
|
||||
if (!skb_match) {
|
||||
dev_warn_ratelimited(ocelot->dev,
|
||||
"port %d received TX timestamp (seqid %d, ts id %u) for packet previously declared stale\n",
|
||||
txport, seqid, id);
|
||||
goto next_ts;
|
||||
}
|
||||
|
||||
/* Get the h/w timestamp */
|
||||
@ -802,7 +851,7 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
|
||||
shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
|
||||
skb_complete_tx_timestamp(skb_match, &shhwtstamps);
|
||||
|
||||
/* Next ts */
|
||||
next_ts:
|
||||
ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT);
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ MODULE_PARM_DESC(qcaspi_burst_len, "Number of data bytes per burst. Use 1-5000."
|
||||
|
||||
#define QCASPI_PLUGGABLE_MIN 0
|
||||
#define QCASPI_PLUGGABLE_MAX 1
|
||||
static int qcaspi_pluggable = QCASPI_PLUGGABLE_MIN;
|
||||
static int qcaspi_pluggable = QCASPI_PLUGGABLE_MAX;
|
||||
module_param(qcaspi_pluggable, int, 0);
|
||||
MODULE_PARM_DESC(qcaspi_pluggable, "Pluggable SPI connection (yes/no).");
|
||||
|
||||
@ -818,7 +818,6 @@ qcaspi_netdev_init(struct net_device *dev)
|
||||
|
||||
dev->mtu = QCAFRM_MAX_MTU;
|
||||
dev->type = ARPHRD_ETHER;
|
||||
qca->clkspeed = qcaspi_clkspeed;
|
||||
qca->burst_len = qcaspi_burst_len;
|
||||
qca->spi_thread = NULL;
|
||||
qca->buffer_size = (QCAFRM_MAX_MTU + VLAN_ETH_HLEN + QCAFRM_HEADER_LEN +
|
||||
@ -909,17 +908,15 @@ qca_spi_probe(struct spi_device *spi)
|
||||
legacy_mode = of_property_read_bool(spi->dev.of_node,
|
||||
"qca,legacy-mode");
|
||||
|
||||
if (qcaspi_clkspeed == 0) {
|
||||
if (spi->max_speed_hz)
|
||||
qcaspi_clkspeed = spi->max_speed_hz;
|
||||
else
|
||||
qcaspi_clkspeed = QCASPI_CLK_SPEED;
|
||||
}
|
||||
if (qcaspi_clkspeed)
|
||||
spi->max_speed_hz = qcaspi_clkspeed;
|
||||
else if (!spi->max_speed_hz)
|
||||
spi->max_speed_hz = QCASPI_CLK_SPEED;
|
||||
|
||||
if ((qcaspi_clkspeed < QCASPI_CLK_SPEED_MIN) ||
|
||||
(qcaspi_clkspeed > QCASPI_CLK_SPEED_MAX)) {
|
||||
dev_err(&spi->dev, "Invalid clkspeed: %d\n",
|
||||
qcaspi_clkspeed);
|
||||
if (spi->max_speed_hz < QCASPI_CLK_SPEED_MIN ||
|
||||
spi->max_speed_hz > QCASPI_CLK_SPEED_MAX) {
|
||||
dev_err(&spi->dev, "Invalid clkspeed: %u\n",
|
||||
spi->max_speed_hz);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -944,14 +941,13 @@ qca_spi_probe(struct spi_device *spi)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_info(&spi->dev, "ver=%s, clkspeed=%d, burst_len=%d, pluggable=%d\n",
|
||||
dev_info(&spi->dev, "ver=%s, clkspeed=%u, burst_len=%d, pluggable=%d\n",
|
||||
QCASPI_DRV_VERSION,
|
||||
qcaspi_clkspeed,
|
||||
spi->max_speed_hz,
|
||||
qcaspi_burst_len,
|
||||
qcaspi_pluggable);
|
||||
|
||||
spi->mode = SPI_MODE_3;
|
||||
spi->max_speed_hz = qcaspi_clkspeed;
|
||||
if (spi_setup(spi) < 0) {
|
||||
dev_err(&spi->dev, "Unable to setup SPI device\n");
|
||||
return -EFAULT;
|
||||
|
@ -89,7 +89,6 @@ struct qcaspi {
|
||||
#endif
|
||||
|
||||
/* user configurable options */
|
||||
u32 clkspeed;
|
||||
u8 legacy_mode;
|
||||
u16 burst_len;
|
||||
};
|
||||
|
@ -862,13 +862,10 @@ static void rswitch_tx_free(struct net_device *ndev)
|
||||
struct rswitch_ext_desc *desc;
|
||||
struct sk_buff *skb;
|
||||
|
||||
for (; rswitch_get_num_cur_queues(gq) > 0;
|
||||
gq->dirty = rswitch_next_queue_index(gq, false, 1)) {
|
||||
desc = &gq->tx_ring[gq->dirty];
|
||||
if ((desc->desc.die_dt & DT_MASK) != DT_FEMPTY)
|
||||
break;
|
||||
|
||||
desc = &gq->tx_ring[gq->dirty];
|
||||
while ((desc->desc.die_dt & DT_MASK) == DT_FEMPTY) {
|
||||
dma_rmb();
|
||||
|
||||
skb = gq->skbs[gq->dirty];
|
||||
if (skb) {
|
||||
rdev->ndev->stats.tx_packets++;
|
||||
@ -879,7 +876,10 @@ static void rswitch_tx_free(struct net_device *ndev)
|
||||
dev_kfree_skb_any(gq->skbs[gq->dirty]);
|
||||
gq->skbs[gq->dirty] = NULL;
|
||||
}
|
||||
|
||||
desc->desc.die_dt = DT_EEMPTY;
|
||||
gq->dirty = rswitch_next_queue_index(gq, false, 1);
|
||||
desc = &gq->tx_ring[gq->dirty];
|
||||
}
|
||||
}
|
||||
|
||||
@ -908,8 +908,10 @@ static int rswitch_poll(struct napi_struct *napi, int budget)
|
||||
|
||||
if (napi_complete_done(napi, budget - quota)) {
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true);
|
||||
rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true);
|
||||
if (test_bit(rdev->port, priv->opened_ports)) {
|
||||
rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true);
|
||||
rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true);
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
@ -1114,25 +1116,40 @@ static int rswitch_etha_wait_link_verification(struct rswitch_etha *etha)
|
||||
|
||||
static void rswitch_rmac_setting(struct rswitch_etha *etha, const u8 *mac)
|
||||
{
|
||||
u32 val;
|
||||
u32 pis, lsc;
|
||||
|
||||
rswitch_etha_write_mac_address(etha, mac);
|
||||
|
||||
switch (etha->speed) {
|
||||
case 100:
|
||||
val = MPIC_LSC_100M;
|
||||
switch (etha->phy_interface) {
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
pis = MPIC_PIS_GMII;
|
||||
break;
|
||||
case 1000:
|
||||
val = MPIC_LSC_1G;
|
||||
break;
|
||||
case 2500:
|
||||
val = MPIC_LSC_2_5G;
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
case PHY_INTERFACE_MODE_5GBASER:
|
||||
pis = MPIC_PIS_XGMII;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
pis = FIELD_GET(MPIC_PIS, ioread32(etha->addr + MPIC));
|
||||
break;
|
||||
}
|
||||
|
||||
iowrite32(MPIC_PIS_GMII | val, etha->addr + MPIC);
|
||||
switch (etha->speed) {
|
||||
case 100:
|
||||
lsc = MPIC_LSC_100M;
|
||||
break;
|
||||
case 1000:
|
||||
lsc = MPIC_LSC_1G;
|
||||
break;
|
||||
case 2500:
|
||||
lsc = MPIC_LSC_2_5G;
|
||||
break;
|
||||
default:
|
||||
lsc = FIELD_GET(MPIC_LSC, ioread32(etha->addr + MPIC));
|
||||
break;
|
||||
}
|
||||
|
||||
rswitch_modify(etha->addr, MPIC, MPIC_PIS | MPIC_LSC,
|
||||
FIELD_PREP(MPIC_PIS, pis) | FIELD_PREP(MPIC_LSC, lsc));
|
||||
}
|
||||
|
||||
static void rswitch_etha_enable_mii(struct rswitch_etha *etha)
|
||||
@ -1538,20 +1555,20 @@ static int rswitch_open(struct net_device *ndev)
|
||||
struct rswitch_device *rdev = netdev_priv(ndev);
|
||||
unsigned long flags;
|
||||
|
||||
phy_start(ndev->phydev);
|
||||
if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS))
|
||||
iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDIE);
|
||||
|
||||
napi_enable(&rdev->napi);
|
||||
netif_start_queue(ndev);
|
||||
|
||||
spin_lock_irqsave(&rdev->priv->lock, flags);
|
||||
bitmap_set(rdev->priv->opened_ports, rdev->port, 1);
|
||||
rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, true);
|
||||
rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, true);
|
||||
spin_unlock_irqrestore(&rdev->priv->lock, flags);
|
||||
|
||||
if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS))
|
||||
iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDIE);
|
||||
phy_start(ndev->phydev);
|
||||
|
||||
bitmap_set(rdev->priv->opened_ports, rdev->port, 1);
|
||||
netif_start_queue(ndev);
|
||||
|
||||
return 0;
|
||||
};
|
||||
@ -1563,7 +1580,16 @@ static int rswitch_stop(struct net_device *ndev)
|
||||
unsigned long flags;
|
||||
|
||||
netif_tx_stop_all_queues(ndev);
|
||||
|
||||
phy_stop(ndev->phydev);
|
||||
|
||||
spin_lock_irqsave(&rdev->priv->lock, flags);
|
||||
rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false);
|
||||
rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false);
|
||||
bitmap_clear(rdev->priv->opened_ports, rdev->port, 1);
|
||||
spin_unlock_irqrestore(&rdev->priv->lock, flags);
|
||||
|
||||
napi_disable(&rdev->napi);
|
||||
|
||||
if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS))
|
||||
iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDID);
|
||||
@ -1576,14 +1602,6 @@ static int rswitch_stop(struct net_device *ndev)
|
||||
kfree(ts_info);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&rdev->priv->lock, flags);
|
||||
rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false);
|
||||
rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false);
|
||||
spin_unlock_irqrestore(&rdev->priv->lock, flags);
|
||||
|
||||
phy_stop(ndev->phydev);
|
||||
napi_disable(&rdev->napi);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
@ -1681,8 +1699,11 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd
|
||||
if (dma_mapping_error(ndev->dev.parent, dma_addr_orig))
|
||||
goto err_kfree;
|
||||
|
||||
gq->skbs[gq->cur] = skb;
|
||||
gq->unmap_addrs[gq->cur] = dma_addr_orig;
|
||||
/* Stored the skb at the last descriptor to avoid skb free before hardware completes send */
|
||||
gq->skbs[(gq->cur + nr_desc - 1) % gq->ring_size] = skb;
|
||||
gq->unmap_addrs[(gq->cur + nr_desc - 1) % gq->ring_size] = dma_addr_orig;
|
||||
|
||||
dma_wmb();
|
||||
|
||||
/* DT_FSTART should be set at last. So, this is reverse order. */
|
||||
for (i = nr_desc; i-- > 0; ) {
|
||||
@ -1694,14 +1715,13 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
wmb(); /* gq->cur must be incremented after die_dt was set */
|
||||
|
||||
gq->cur = rswitch_next_queue_index(gq, true, nr_desc);
|
||||
rswitch_modify(rdev->addr, GWTRC(gq->index), 0, BIT(gq->index % 32));
|
||||
|
||||
return ret;
|
||||
|
||||
err_unmap:
|
||||
gq->skbs[(gq->cur + nr_desc - 1) % gq->ring_size] = NULL;
|
||||
dma_unmap_single(ndev->dev.parent, dma_addr_orig, skb->len, DMA_TO_DEVICE);
|
||||
|
||||
err_kfree:
|
||||
@ -1889,7 +1909,6 @@ static int rswitch_device_alloc(struct rswitch_private *priv, unsigned int index
|
||||
rdev->np_port = rswitch_get_port_node(rdev);
|
||||
rdev->disabled = !rdev->np_port;
|
||||
err = of_get_ethdev_address(rdev->np_port, ndev);
|
||||
of_node_put(rdev->np_port);
|
||||
if (err) {
|
||||
if (is_valid_ether_addr(rdev->etha->mac_addr))
|
||||
eth_hw_addr_set(ndev, rdev->etha->mac_addr);
|
||||
@ -1919,6 +1938,7 @@ static int rswitch_device_alloc(struct rswitch_private *priv, unsigned int index
|
||||
|
||||
out_rxdmac:
|
||||
out_get_params:
|
||||
of_node_put(rdev->np_port);
|
||||
netif_napi_del(&rdev->napi);
|
||||
free_netdev(ndev);
|
||||
|
||||
@ -1932,6 +1952,7 @@ static void rswitch_device_free(struct rswitch_private *priv, unsigned int index
|
||||
|
||||
rswitch_txdmac_free(ndev);
|
||||
rswitch_rxdmac_free(ndev);
|
||||
of_node_put(rdev->np_port);
|
||||
netif_napi_del(&rdev->napi);
|
||||
free_netdev(ndev);
|
||||
}
|
||||
|
@ -724,13 +724,13 @@ enum rswitch_etha_mode {
|
||||
|
||||
#define EAVCC_VEM_SC_TAG (0x3 << 16)
|
||||
|
||||
#define MPIC_PIS_MII 0x00
|
||||
#define MPIC_PIS_GMII 0x02
|
||||
#define MPIC_PIS_XGMII 0x04
|
||||
#define MPIC_LSC_SHIFT 3
|
||||
#define MPIC_LSC_100M (1 << MPIC_LSC_SHIFT)
|
||||
#define MPIC_LSC_1G (2 << MPIC_LSC_SHIFT)
|
||||
#define MPIC_LSC_2_5G (3 << MPIC_LSC_SHIFT)
|
||||
#define MPIC_PIS GENMASK(2, 0)
|
||||
#define MPIC_PIS_GMII 2
|
||||
#define MPIC_PIS_XGMII 4
|
||||
#define MPIC_LSC GENMASK(5, 3)
|
||||
#define MPIC_LSC_100M 1
|
||||
#define MPIC_LSC_1G 2
|
||||
#define MPIC_LSC_2_5G 3
|
||||
|
||||
#define MDIO_READ_C45 0x03
|
||||
#define MDIO_WRITE_C45 0x01
|
||||
|
@ -4192,8 +4192,8 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
struct stmmac_txq_stats *txq_stats;
|
||||
struct stmmac_tx_queue *tx_q;
|
||||
u32 pay_len, mss, queue;
|
||||
dma_addr_t tso_des, des;
|
||||
u8 proto_hdr_len, hdr;
|
||||
dma_addr_t des;
|
||||
bool set_ic;
|
||||
int i;
|
||||
|
||||
@ -4289,14 +4289,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
|
||||
/* If needed take extra descriptors to fill the remaining payload */
|
||||
tmp_pay_len = pay_len - TSO_MAX_BUFF_SIZE;
|
||||
tso_des = des;
|
||||
} else {
|
||||
stmmac_set_desc_addr(priv, first, des);
|
||||
tmp_pay_len = pay_len;
|
||||
des += proto_hdr_len;
|
||||
tso_des = des + proto_hdr_len;
|
||||
pay_len = 0;
|
||||
}
|
||||
|
||||
stmmac_tso_allocator(priv, des, tmp_pay_len, (nfrags == 0), queue);
|
||||
stmmac_tso_allocator(priv, tso_des, tmp_pay_len, (nfrags == 0), queue);
|
||||
|
||||
/* In case two or more DMA transmit descriptors are allocated for this
|
||||
* non-paged SKB data, the DMA buffer address should be saved to
|
||||
|
@ -983,7 +983,8 @@ static void team_port_disable(struct team *team,
|
||||
|
||||
#define TEAM_VLAN_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
|
||||
NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | \
|
||||
NETIF_F_HIGHDMA | NETIF_F_LRO)
|
||||
NETIF_F_HIGHDMA | NETIF_F_LRO | \
|
||||
NETIF_F_GSO_ENCAP_ALL)
|
||||
|
||||
#define TEAM_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
|
||||
NETIF_F_RXCSUM | NETIF_F_GSO_SOFTWARE)
|
||||
@ -991,13 +992,14 @@ static void team_port_disable(struct team *team,
|
||||
static void __team_compute_features(struct team *team)
|
||||
{
|
||||
struct team_port *port;
|
||||
netdev_features_t vlan_features = TEAM_VLAN_FEATURES &
|
||||
NETIF_F_ALL_FOR_ALL;
|
||||
netdev_features_t vlan_features = TEAM_VLAN_FEATURES;
|
||||
netdev_features_t enc_features = TEAM_ENC_FEATURES;
|
||||
unsigned short max_hard_header_len = ETH_HLEN;
|
||||
unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE |
|
||||
IFF_XMIT_DST_RELEASE_PERM;
|
||||
|
||||
vlan_features = netdev_base_features(vlan_features);
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(port, &team->port_list, list) {
|
||||
vlan_features = netdev_increment_features(vlan_features,
|
||||
@ -2011,8 +2013,7 @@ static netdev_features_t team_fix_features(struct net_device *dev,
|
||||
netdev_features_t mask;
|
||||
|
||||
mask = features;
|
||||
features &= ~NETIF_F_ONE_FOR_ALL;
|
||||
features |= NETIF_F_ALL_FOR_ALL;
|
||||
features = netdev_base_features(features);
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(port, &team->port_list, list) {
|
||||
|
@ -1365,6 +1365,9 @@ static const struct usb_device_id products[] = {
|
||||
{QMI_QUIRK_SET_DTR(0x1bc7, 0x10a0, 0)}, /* Telit FN920C04 */
|
||||
{QMI_QUIRK_SET_DTR(0x1bc7, 0x10a4, 0)}, /* Telit FN920C04 */
|
||||
{QMI_QUIRK_SET_DTR(0x1bc7, 0x10a9, 0)}, /* Telit FN920C04 */
|
||||
{QMI_QUIRK_SET_DTR(0x1bc7, 0x10c0, 0)}, /* Telit FE910C04 */
|
||||
{QMI_QUIRK_SET_DTR(0x1bc7, 0x10c4, 0)}, /* Telit FE910C04 */
|
||||
{QMI_QUIRK_SET_DTR(0x1bc7, 0x10c8, 0)}, /* Telit FE910C04 */
|
||||
{QMI_FIXED_INTF(0x1bc7, 0x1100, 3)}, /* Telit ME910 */
|
||||
{QMI_FIXED_INTF(0x1bc7, 0x1101, 3)}, /* Telit ME910 dual modem */
|
||||
{QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */
|
||||
|
@ -503,6 +503,7 @@ struct virtio_net_common_hdr {
|
||||
static struct virtio_net_common_hdr xsk_hdr;
|
||||
|
||||
static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);
|
||||
static void virtnet_sq_free_unused_buf_done(struct virtqueue *vq);
|
||||
static int virtnet_xdp_handler(struct bpf_prog *xdp_prog, struct xdp_buff *xdp,
|
||||
struct net_device *dev,
|
||||
unsigned int *xdp_xmit,
|
||||
@ -3054,7 +3055,6 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
|
||||
if (err < 0)
|
||||
goto err_xdp_reg_mem_model;
|
||||
|
||||
netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, qp_index));
|
||||
virtnet_napi_enable(vi->rq[qp_index].vq, &vi->rq[qp_index].napi);
|
||||
virtnet_napi_tx_enable(vi, vi->sq[qp_index].vq, &vi->sq[qp_index].napi);
|
||||
|
||||
@ -3332,7 +3332,7 @@ static int virtnet_rx_resize(struct virtnet_info *vi,
|
||||
|
||||
virtnet_rx_pause(vi, rq);
|
||||
|
||||
err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf);
|
||||
err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf, NULL);
|
||||
if (err)
|
||||
netdev_err(vi->dev, "resize rx fail: rx queue index: %d err: %d\n", qindex, err);
|
||||
|
||||
@ -3395,7 +3395,8 @@ static int virtnet_tx_resize(struct virtnet_info *vi, struct send_queue *sq,
|
||||
|
||||
virtnet_tx_pause(vi, sq);
|
||||
|
||||
err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf);
|
||||
err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf,
|
||||
virtnet_sq_free_unused_buf_done);
|
||||
if (err)
|
||||
netdev_err(vi->dev, "resize tx fail: tx queue index: %d err: %d\n", qindex, err);
|
||||
|
||||
@ -5710,7 +5711,7 @@ static int virtnet_rq_bind_xsk_pool(struct virtnet_info *vi, struct receive_queu
|
||||
|
||||
virtnet_rx_pause(vi, rq);
|
||||
|
||||
err = virtqueue_reset(rq->vq, virtnet_rq_unmap_free_buf);
|
||||
err = virtqueue_reset(rq->vq, virtnet_rq_unmap_free_buf, NULL);
|
||||
if (err) {
|
||||
netdev_err(vi->dev, "reset rx fail: rx queue index: %d err: %d\n", qindex, err);
|
||||
|
||||
@ -5739,7 +5740,8 @@ static int virtnet_sq_bind_xsk_pool(struct virtnet_info *vi,
|
||||
|
||||
virtnet_tx_pause(vi, sq);
|
||||
|
||||
err = virtqueue_reset(sq->vq, virtnet_sq_free_unused_buf);
|
||||
err = virtqueue_reset(sq->vq, virtnet_sq_free_unused_buf,
|
||||
virtnet_sq_free_unused_buf_done);
|
||||
if (err) {
|
||||
netdev_err(vi->dev, "reset tx fail: tx queue index: %d err: %d\n", qindex, err);
|
||||
pool = NULL;
|
||||
@ -6214,7 +6216,7 @@ static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf)
|
||||
{
|
||||
struct virtnet_info *vi = vq->vdev->priv;
|
||||
struct send_queue *sq;
|
||||
int i = vq2rxq(vq);
|
||||
int i = vq2txq(vq);
|
||||
|
||||
sq = &vi->sq[i];
|
||||
|
||||
@ -6234,6 +6236,14 @@ static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf)
|
||||
}
|
||||
}
|
||||
|
||||
static void virtnet_sq_free_unused_buf_done(struct virtqueue *vq)
|
||||
{
|
||||
struct virtnet_info *vi = vq->vdev->priv;
|
||||
int i = vq2txq(vq);
|
||||
|
||||
netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, i));
|
||||
}
|
||||
|
||||
static void free_unused_bufs(struct virtnet_info *vi)
|
||||
{
|
||||
void *buf;
|
||||
@ -6966,11 +6976,20 @@ static int virtnet_probe(struct virtio_device *vdev)
|
||||
|
||||
static void remove_vq_common(struct virtnet_info *vi)
|
||||
{
|
||||
int i;
|
||||
|
||||
virtio_reset_device(vi->vdev);
|
||||
|
||||
/* Free unused buffers in both send and recv, if any. */
|
||||
free_unused_bufs(vi);
|
||||
|
||||
/*
|
||||
* Rule of thumb is netdev_tx_reset_queue() should follow any
|
||||
* skb freeing not followed by netdev_tx_completed_queue()
|
||||
*/
|
||||
for (i = 0; i < vi->max_queue_pairs; i++)
|
||||
netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, i));
|
||||
|
||||
free_receive_bufs(vi);
|
||||
|
||||
free_receive_page_frags(vi);
|
||||
|
@ -1972,7 +1972,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm,
|
||||
if (csa_err_mask & (CS_ERR_COUNT_ERROR |
|
||||
CS_ERR_LONG_DELAY_AFTER_CS |
|
||||
CS_ERR_TX_BLOCK_TIMER_EXPIRED))
|
||||
ieee80211_channel_switch_disconnect(vif, true);
|
||||
ieee80211_channel_switch_disconnect(vif);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ int kvm_arch_ptp_init(void)
|
||||
long ret;
|
||||
|
||||
if (!kvm_para_available())
|
||||
return -ENODEV;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {
|
||||
p = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
||||
@ -46,14 +46,14 @@ int kvm_arch_ptp_init(void)
|
||||
|
||||
clock_pair_gpa = slow_virt_to_phys(clock_pair);
|
||||
if (!pvclock_get_pvti_cpu0_va()) {
|
||||
ret = -ENODEV;
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
|
||||
KVM_CLOCK_PAIRING_WALLCLOCK);
|
||||
if (ret == -KVM_ENOSYS) {
|
||||
ret = -ENODEV;
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -2772,6 +2772,7 @@ EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma);
|
||||
* @_vq: the struct virtqueue we're talking about.
|
||||
* @num: new ring num
|
||||
* @recycle: callback to recycle unused buffers
|
||||
* @recycle_done: callback to be invoked when recycle for all unused buffers done
|
||||
*
|
||||
* When it is really necessary to create a new vring, it will set the current vq
|
||||
* into the reset state. Then call the passed callback to recycle the buffer
|
||||
@ -2792,7 +2793,8 @@ EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma);
|
||||
*
|
||||
*/
|
||||
int virtqueue_resize(struct virtqueue *_vq, u32 num,
|
||||
void (*recycle)(struct virtqueue *vq, void *buf))
|
||||
void (*recycle)(struct virtqueue *vq, void *buf),
|
||||
void (*recycle_done)(struct virtqueue *vq))
|
||||
{
|
||||
struct vring_virtqueue *vq = to_vvq(_vq);
|
||||
int err;
|
||||
@ -2809,6 +2811,8 @@ int virtqueue_resize(struct virtqueue *_vq, u32 num,
|
||||
err = virtqueue_disable_and_recycle(_vq, recycle);
|
||||
if (err)
|
||||
return err;
|
||||
if (recycle_done)
|
||||
recycle_done(_vq);
|
||||
|
||||
if (vq->packed_ring)
|
||||
err = virtqueue_resize_packed(_vq, num);
|
||||
@ -2823,6 +2827,7 @@ EXPORT_SYMBOL_GPL(virtqueue_resize);
|
||||
* virtqueue_reset - detach and recycle all unused buffers
|
||||
* @_vq: the struct virtqueue we're talking about.
|
||||
* @recycle: callback to recycle unused buffers
|
||||
* @recycle_done: callback to be invoked when recycle for all unused buffers done
|
||||
*
|
||||
* Caller must ensure we don't call this with other virtqueue operations
|
||||
* at the same time (except where noted).
|
||||
@ -2834,7 +2839,8 @@ EXPORT_SYMBOL_GPL(virtqueue_resize);
|
||||
* -EPERM: Operation not permitted
|
||||
*/
|
||||
int virtqueue_reset(struct virtqueue *_vq,
|
||||
void (*recycle)(struct virtqueue *vq, void *buf))
|
||||
void (*recycle)(struct virtqueue *vq, void *buf),
|
||||
void (*recycle_done)(struct virtqueue *vq))
|
||||
{
|
||||
struct vring_virtqueue *vq = to_vvq(_vq);
|
||||
int err;
|
||||
@ -2842,6 +2848,8 @@ int virtqueue_reset(struct virtqueue *_vq,
|
||||
err = virtqueue_disable_and_recycle(_vq, recycle);
|
||||
if (err)
|
||||
return err;
|
||||
if (recycle_done)
|
||||
recycle_done(_vq);
|
||||
|
||||
if (vq->packed_ring)
|
||||
virtqueue_reinit_packed(vq);
|
||||
|
@ -15,6 +15,7 @@
|
||||
struct ocelot_skb_cb {
|
||||
struct sk_buff *clone;
|
||||
unsigned int ptp_class; /* valid only for clones */
|
||||
unsigned long ptp_tx_time; /* valid only for clones */
|
||||
u32 tstamp_lo;
|
||||
u8 ptp_cmd;
|
||||
u8 ts_id;
|
||||
|
@ -253,4 +253,11 @@ static inline int find_next_netdev_feature(u64 feature, unsigned long start)
|
||||
NETIF_F_GSO_UDP_TUNNEL | \
|
||||
NETIF_F_GSO_UDP_TUNNEL_CSUM)
|
||||
|
||||
static inline netdev_features_t netdev_base_features(netdev_features_t features)
|
||||
{
|
||||
features &= ~NETIF_F_ONE_FOR_ALL;
|
||||
features |= NETIF_F_ALL_FOR_ALL;
|
||||
return features;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_NETDEV_FEATURES_H */
|
||||
|
@ -109,9 +109,11 @@ dma_addr_t virtqueue_get_avail_addr(const struct virtqueue *vq);
|
||||
dma_addr_t virtqueue_get_used_addr(const struct virtqueue *vq);
|
||||
|
||||
int virtqueue_resize(struct virtqueue *vq, u32 num,
|
||||
void (*recycle)(struct virtqueue *vq, void *buf));
|
||||
void (*recycle)(struct virtqueue *vq, void *buf),
|
||||
void (*recycle_done)(struct virtqueue *vq));
|
||||
int virtqueue_reset(struct virtqueue *vq,
|
||||
void (*recycle)(struct virtqueue *vq, void *buf));
|
||||
void (*recycle)(struct virtqueue *vq, void *buf),
|
||||
void (*recycle_done)(struct virtqueue *vq));
|
||||
|
||||
struct virtio_admin_cmd {
|
||||
__le16 opcode;
|
||||
|
@ -123,6 +123,7 @@ struct bt_voice {
|
||||
|
||||
#define BT_VOICE_TRANSPARENT 0x0003
|
||||
#define BT_VOICE_CVSD_16BIT 0x0060
|
||||
#define BT_VOICE_TRANSPARENT_16BIT 0x0063
|
||||
|
||||
#define BT_SNDMTU 12
|
||||
#define BT_RCVMTU 13
|
||||
@ -590,15 +591,6 @@ static inline struct sk_buff *bt_skb_sendmmsg(struct sock *sk,
|
||||
return skb;
|
||||
}
|
||||
|
||||
static inline int bt_copy_from_sockptr(void *dst, size_t dst_size,
|
||||
sockptr_t src, size_t src_size)
|
||||
{
|
||||
if (dst_size > src_size)
|
||||
return -EINVAL;
|
||||
|
||||
return copy_from_sockptr(dst, src, dst_size);
|
||||
}
|
||||
|
||||
int bt_to_errno(u16 code);
|
||||
__u8 bt_status(int err);
|
||||
|
||||
|
@ -804,7 +804,6 @@ struct hci_conn_params {
|
||||
extern struct list_head hci_dev_list;
|
||||
extern struct list_head hci_cb_list;
|
||||
extern rwlock_t hci_dev_list_lock;
|
||||
extern struct mutex hci_cb_list_lock;
|
||||
|
||||
#define hci_dev_set_flag(hdev, nr) set_bit((nr), (hdev)->dev_flags)
|
||||
#define hci_dev_clear_flag(hdev, nr) clear_bit((nr), (hdev)->dev_flags)
|
||||
@ -2017,24 +2016,47 @@ struct hci_cb {
|
||||
|
||||
char *name;
|
||||
|
||||
bool (*match) (struct hci_conn *conn);
|
||||
void (*connect_cfm) (struct hci_conn *conn, __u8 status);
|
||||
void (*disconn_cfm) (struct hci_conn *conn, __u8 status);
|
||||
void (*security_cfm) (struct hci_conn *conn, __u8 status,
|
||||
__u8 encrypt);
|
||||
__u8 encrypt);
|
||||
void (*key_change_cfm) (struct hci_conn *conn, __u8 status);
|
||||
void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role);
|
||||
};
|
||||
|
||||
static inline void hci_cb_lookup(struct hci_conn *conn, struct list_head *list)
|
||||
{
|
||||
struct hci_cb *cb, *cpy;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(cb, &hci_cb_list, list) {
|
||||
if (cb->match && cb->match(conn)) {
|
||||
cpy = kmalloc(sizeof(*cpy), GFP_ATOMIC);
|
||||
if (!cpy)
|
||||
break;
|
||||
|
||||
*cpy = *cb;
|
||||
INIT_LIST_HEAD(&cpy->list);
|
||||
list_add_rcu(&cpy->list, list);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static inline void hci_connect_cfm(struct hci_conn *conn, __u8 status)
|
||||
{
|
||||
struct hci_cb *cb;
|
||||
struct list_head list;
|
||||
struct hci_cb *cb, *tmp;
|
||||
|
||||
mutex_lock(&hci_cb_list_lock);
|
||||
list_for_each_entry(cb, &hci_cb_list, list) {
|
||||
INIT_LIST_HEAD(&list);
|
||||
hci_cb_lookup(conn, &list);
|
||||
|
||||
list_for_each_entry_safe(cb, tmp, &list, list) {
|
||||
if (cb->connect_cfm)
|
||||
cb->connect_cfm(conn, status);
|
||||
kfree(cb);
|
||||
}
|
||||
mutex_unlock(&hci_cb_list_lock);
|
||||
|
||||
if (conn->connect_cfm_cb)
|
||||
conn->connect_cfm_cb(conn, status);
|
||||
@ -2042,22 +2064,43 @@ static inline void hci_connect_cfm(struct hci_conn *conn, __u8 status)
|
||||
|
||||
static inline void hci_disconn_cfm(struct hci_conn *conn, __u8 reason)
|
||||
{
|
||||
struct hci_cb *cb;
|
||||
struct list_head list;
|
||||
struct hci_cb *cb, *tmp;
|
||||
|
||||
mutex_lock(&hci_cb_list_lock);
|
||||
list_for_each_entry(cb, &hci_cb_list, list) {
|
||||
INIT_LIST_HEAD(&list);
|
||||
hci_cb_lookup(conn, &list);
|
||||
|
||||
list_for_each_entry_safe(cb, tmp, &list, list) {
|
||||
if (cb->disconn_cfm)
|
||||
cb->disconn_cfm(conn, reason);
|
||||
kfree(cb);
|
||||
}
|
||||
mutex_unlock(&hci_cb_list_lock);
|
||||
|
||||
if (conn->disconn_cfm_cb)
|
||||
conn->disconn_cfm_cb(conn, reason);
|
||||
}
|
||||
|
||||
static inline void hci_security_cfm(struct hci_conn *conn, __u8 status,
|
||||
__u8 encrypt)
|
||||
{
|
||||
struct list_head list;
|
||||
struct hci_cb *cb, *tmp;
|
||||
|
||||
INIT_LIST_HEAD(&list);
|
||||
hci_cb_lookup(conn, &list);
|
||||
|
||||
list_for_each_entry_safe(cb, tmp, &list, list) {
|
||||
if (cb->security_cfm)
|
||||
cb->security_cfm(conn, status, encrypt);
|
||||
kfree(cb);
|
||||
}
|
||||
|
||||
if (conn->security_cfm_cb)
|
||||
conn->security_cfm_cb(conn, status);
|
||||
}
|
||||
|
||||
static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
|
||||
{
|
||||
struct hci_cb *cb;
|
||||
__u8 encrypt;
|
||||
|
||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
|
||||
@ -2065,20 +2108,11 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
|
||||
|
||||
encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00;
|
||||
|
||||
mutex_lock(&hci_cb_list_lock);
|
||||
list_for_each_entry(cb, &hci_cb_list, list) {
|
||||
if (cb->security_cfm)
|
||||
cb->security_cfm(conn, status, encrypt);
|
||||
}
|
||||
mutex_unlock(&hci_cb_list_lock);
|
||||
|
||||
if (conn->security_cfm_cb)
|
||||
conn->security_cfm_cb(conn, status);
|
||||
hci_security_cfm(conn, status, encrypt);
|
||||
}
|
||||
|
||||
static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status)
|
||||
{
|
||||
struct hci_cb *cb;
|
||||
__u8 encrypt;
|
||||
|
||||
if (conn->state == BT_CONFIG) {
|
||||
@ -2105,40 +2139,38 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status)
|
||||
conn->sec_level = conn->pending_sec_level;
|
||||
}
|
||||
|
||||
mutex_lock(&hci_cb_list_lock);
|
||||
list_for_each_entry(cb, &hci_cb_list, list) {
|
||||
if (cb->security_cfm)
|
||||
cb->security_cfm(conn, status, encrypt);
|
||||
}
|
||||
mutex_unlock(&hci_cb_list_lock);
|
||||
|
||||
if (conn->security_cfm_cb)
|
||||
conn->security_cfm_cb(conn, status);
|
||||
hci_security_cfm(conn, status, encrypt);
|
||||
}
|
||||
|
||||
static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
|
||||
{
|
||||
struct hci_cb *cb;
|
||||
struct list_head list;
|
||||
struct hci_cb *cb, *tmp;
|
||||
|
||||
mutex_lock(&hci_cb_list_lock);
|
||||
list_for_each_entry(cb, &hci_cb_list, list) {
|
||||
INIT_LIST_HEAD(&list);
|
||||
hci_cb_lookup(conn, &list);
|
||||
|
||||
list_for_each_entry_safe(cb, tmp, &list, list) {
|
||||
if (cb->key_change_cfm)
|
||||
cb->key_change_cfm(conn, status);
|
||||
kfree(cb);
|
||||
}
|
||||
mutex_unlock(&hci_cb_list_lock);
|
||||
}
|
||||
|
||||
static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
|
||||
__u8 role)
|
||||
{
|
||||
struct hci_cb *cb;
|
||||
struct list_head list;
|
||||
struct hci_cb *cb, *tmp;
|
||||
|
||||
mutex_lock(&hci_cb_list_lock);
|
||||
list_for_each_entry(cb, &hci_cb_list, list) {
|
||||
INIT_LIST_HEAD(&list);
|
||||
hci_cb_lookup(conn, &list);
|
||||
|
||||
list_for_each_entry_safe(cb, tmp, &list, list) {
|
||||
if (cb->role_switch_cfm)
|
||||
cb->role_switch_cfm(conn, status, role);
|
||||
kfree(cb);
|
||||
}
|
||||
mutex_unlock(&hci_cb_list_lock);
|
||||
}
|
||||
|
||||
static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type)
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <linux/lapb.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
#define LAPB_HEADER_LEN 20 /* LAPB over Ethernet + a bit more */
|
||||
#define LAPB_HEADER_LEN MAX_HEADER /* LAPB over Ethernet + a bit more */
|
||||
|
||||
#define LAPB_ACK_PENDING_CONDITION 0x01
|
||||
#define LAPB_REJECT_CONDITION 0x02
|
||||
|
@ -1987,6 +1987,8 @@ enum ieee80211_neg_ttlm_res {
|
||||
* @neg_ttlm: negotiated TID to link mapping info.
|
||||
* see &struct ieee80211_neg_ttlm.
|
||||
* @addr: address of this interface
|
||||
* @addr_valid: indicates if the address is actively used. Set to false for
|
||||
* passive monitor interfaces, true in all other cases.
|
||||
* @p2p: indicates whether this AP or STA interface is a p2p
|
||||
* interface, i.e. a GO or p2p-sta respectively
|
||||
* @netdev_features: tx netdev features supported by the hardware for this
|
||||
@ -2026,6 +2028,7 @@ struct ieee80211_vif {
|
||||
u16 valid_links, active_links, dormant_links, suspended_links;
|
||||
struct ieee80211_neg_ttlm neg_ttlm;
|
||||
u8 addr[ETH_ALEN] __aligned(2);
|
||||
bool addr_valid;
|
||||
bool p2p;
|
||||
|
||||
u8 cab_queue;
|
||||
@ -6795,14 +6798,12 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success,
|
||||
/**
|
||||
* ieee80211_channel_switch_disconnect - disconnect due to channel switch error
|
||||
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
* @block_tx: if %true, do not send deauth frame.
|
||||
*
|
||||
* Instruct mac80211 to disconnect due to a channel switch error. The channel
|
||||
* switch can request to block the tx and so, we need to make sure we do not send
|
||||
* a deauth frame in this case.
|
||||
*/
|
||||
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif,
|
||||
bool block_tx);
|
||||
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* ieee80211_request_smps - request SM PS transition
|
||||
|
@ -80,6 +80,7 @@ struct net {
|
||||
* or to unregister pernet ops
|
||||
* (pernet_ops_rwsem write locked).
|
||||
*/
|
||||
struct llist_node defer_free_list;
|
||||
struct llist_node cleanup_list; /* namespaces on death row */
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
|
@ -1103,7 +1103,6 @@ struct nft_rule_blob {
|
||||
* @name: name of the chain
|
||||
* @udlen: user data length
|
||||
* @udata: user data in the chain
|
||||
* @rcu_head: rcu head for deferred release
|
||||
* @blob_next: rule blob pointer to the next in the chain
|
||||
*/
|
||||
struct nft_chain {
|
||||
@ -1121,7 +1120,6 @@ struct nft_chain {
|
||||
char *name;
|
||||
u16 udlen;
|
||||
u8 *udata;
|
||||
struct rcu_head rcu_head;
|
||||
|
||||
/* Only used during control plane commit phase: */
|
||||
struct nft_rule_blob *blob_next;
|
||||
@ -1265,7 +1263,6 @@ static inline void nft_use_inc_restore(u32 *use)
|
||||
* @sets: sets in the table
|
||||
* @objects: stateful objects in the table
|
||||
* @flowtables: flow tables in the table
|
||||
* @net: netnamespace this table belongs to
|
||||
* @hgenerator: handle generator state
|
||||
* @handle: table handle
|
||||
* @use: number of chain references to this table
|
||||
@ -1285,7 +1282,6 @@ struct nft_table {
|
||||
struct list_head sets;
|
||||
struct list_head objects;
|
||||
struct list_head flowtables;
|
||||
possible_net_t net;
|
||||
u64 hgenerator;
|
||||
u64 handle;
|
||||
u32 use;
|
||||
|
@ -778,7 +778,6 @@ struct ocelot_port {
|
||||
|
||||
phy_interface_t phy_mode;
|
||||
|
||||
unsigned int ptp_skbs_in_flight;
|
||||
struct sk_buff_head tx_skbs;
|
||||
|
||||
unsigned int trap_proto;
|
||||
@ -786,7 +785,6 @@ struct ocelot_port {
|
||||
u16 mrp_ring_id;
|
||||
|
||||
u8 ptp_cmd;
|
||||
u8 ts_id;
|
||||
|
||||
u8 index;
|
||||
|
||||
|
@ -948,16 +948,25 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
|
||||
int tt_diff_len, tt_change_len = 0;
|
||||
int tt_diff_entries_num = 0;
|
||||
int tt_diff_entries_count = 0;
|
||||
bool drop_changes = false;
|
||||
size_t tt_extra_len = 0;
|
||||
u16 tvlv_len;
|
||||
|
||||
tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes);
|
||||
tt_diff_len = batadv_tt_len(tt_diff_entries_num);
|
||||
|
||||
/* if we have too many changes for one packet don't send any
|
||||
* and wait for the tt table request which will be fragmented
|
||||
* and wait for the tt table request so we can reply with the full
|
||||
* (fragmented) table.
|
||||
*
|
||||
* The local change history should still be cleaned up so the next
|
||||
* TT round can start again with a clean state.
|
||||
*/
|
||||
if (tt_diff_len > bat_priv->soft_iface->mtu)
|
||||
if (tt_diff_len > bat_priv->soft_iface->mtu) {
|
||||
tt_diff_len = 0;
|
||||
tt_diff_entries_num = 0;
|
||||
drop_changes = true;
|
||||
}
|
||||
|
||||
tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
|
||||
&tt_change, &tt_diff_len);
|
||||
@ -966,7 +975,7 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
|
||||
|
||||
tt_data->flags = BATADV_TT_OGM_DIFF;
|
||||
|
||||
if (tt_diff_len == 0)
|
||||
if (!drop_changes && tt_diff_len == 0)
|
||||
goto container_register;
|
||||
|
||||
spin_lock_bh(&bat_priv->tt.changes_list_lock);
|
||||
@ -985,6 +994,9 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
|
||||
}
|
||||
spin_unlock_bh(&bat_priv->tt.changes_list_lock);
|
||||
|
||||
tt_extra_len = batadv_tt_len(tt_diff_entries_num -
|
||||
tt_diff_entries_count);
|
||||
|
||||
/* Keep the buffer for possible tt_request */
|
||||
spin_lock_bh(&bat_priv->tt.last_changeset_lock);
|
||||
kfree(bat_priv->tt.last_changeset);
|
||||
@ -993,6 +1005,7 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
|
||||
tt_change_len = batadv_tt_len(tt_diff_entries_count);
|
||||
/* check whether this new OGM has no changes due to size problems */
|
||||
if (tt_diff_entries_count > 0) {
|
||||
tt_diff_len -= tt_extra_len;
|
||||
/* if kmalloc() fails we will reply with the full table
|
||||
* instead of providing the diff
|
||||
*/
|
||||
@ -1005,6 +1018,8 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
|
||||
}
|
||||
spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
|
||||
|
||||
/* Remove extra packet space for OGM */
|
||||
tvlv_len -= tt_extra_len;
|
||||
container_register:
|
||||
batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data,
|
||||
tvlv_len);
|
||||
@ -2705,14 +2720,16 @@ static bool batadv_tt_global_valid(const void *entry_ptr,
|
||||
*
|
||||
* Fills the tvlv buff with the tt entries from the specified hash. If valid_cb
|
||||
* is not provided then this becomes a no-op.
|
||||
*
|
||||
* Return: Remaining unused length in tvlv_buff.
|
||||
*/
|
||||
static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
|
||||
struct batadv_hashtable *hash,
|
||||
void *tvlv_buff, u16 tt_len,
|
||||
bool (*valid_cb)(const void *,
|
||||
const void *,
|
||||
u8 *flags),
|
||||
void *cb_data)
|
||||
static u16 batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
|
||||
struct batadv_hashtable *hash,
|
||||
void *tvlv_buff, u16 tt_len,
|
||||
bool (*valid_cb)(const void *,
|
||||
const void *,
|
||||
u8 *flags),
|
||||
void *cb_data)
|
||||
{
|
||||
struct batadv_tt_common_entry *tt_common_entry;
|
||||
struct batadv_tvlv_tt_change *tt_change;
|
||||
@ -2726,7 +2743,7 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
|
||||
tt_change = tvlv_buff;
|
||||
|
||||
if (!valid_cb)
|
||||
return;
|
||||
return tt_len;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < hash->size; i++) {
|
||||
@ -2752,6 +2769,8 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return batadv_tt_len(tt_tot - tt_num_entries);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3022,10 +3041,11 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
|
||||
goto out;
|
||||
|
||||
/* fill the rest of the tvlv with the real TT entries */
|
||||
batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash,
|
||||
tt_change, tt_len,
|
||||
batadv_tt_global_valid,
|
||||
req_dst_orig_node);
|
||||
tvlv_len -= batadv_tt_tvlv_generate(bat_priv,
|
||||
bat_priv->tt.global_hash,
|
||||
tt_change, tt_len,
|
||||
batadv_tt_global_valid,
|
||||
req_dst_orig_node);
|
||||
}
|
||||
|
||||
/* Don't send the response, if larger than fragmented packet. */
|
||||
@ -3149,9 +3169,11 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
|
||||
goto out;
|
||||
|
||||
/* fill the rest of the tvlv with the real TT entries */
|
||||
batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash,
|
||||
tt_change, tt_len,
|
||||
batadv_tt_local_valid, NULL);
|
||||
tvlv_len -= batadv_tt_tvlv_generate(bat_priv,
|
||||
bat_priv->tt.local_hash,
|
||||
tt_change, tt_len,
|
||||
batadv_tt_local_valid,
|
||||
NULL);
|
||||
}
|
||||
|
||||
tvlv_tt_data->flags = BATADV_TT_RESPONSE;
|
||||
|
@ -57,7 +57,6 @@ DEFINE_RWLOCK(hci_dev_list_lock);
|
||||
|
||||
/* HCI callback list */
|
||||
LIST_HEAD(hci_cb_list);
|
||||
DEFINE_MUTEX(hci_cb_list_lock);
|
||||
|
||||
/* HCI ID Numbering */
|
||||
static DEFINE_IDA(hci_index_ida);
|
||||
@ -2993,9 +2992,7 @@ int hci_register_cb(struct hci_cb *cb)
|
||||
{
|
||||
BT_DBG("%p name %s", cb, cb->name);
|
||||
|
||||
mutex_lock(&hci_cb_list_lock);
|
||||
list_add_tail(&cb->list, &hci_cb_list);
|
||||
mutex_unlock(&hci_cb_list_lock);
|
||||
list_add_tail_rcu(&cb->list, &hci_cb_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3005,9 +3002,8 @@ int hci_unregister_cb(struct hci_cb *cb)
|
||||
{
|
||||
BT_DBG("%p name %s", cb, cb->name);
|
||||
|
||||
mutex_lock(&hci_cb_list_lock);
|
||||
list_del(&cb->list);
|
||||
mutex_unlock(&hci_cb_list_lock);
|
||||
list_del_rcu(&cb->list);
|
||||
synchronize_rcu();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6870,38 +6870,27 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
rcu_read_lock();
|
||||
|
||||
/* Connect all BISes that are bound to the BIG */
|
||||
list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
|
||||
if (bacmp(&conn->dst, BDADDR_ANY) ||
|
||||
conn->type != ISO_LINK ||
|
||||
conn->iso_qos.bcast.big != ev->handle)
|
||||
while ((conn = hci_conn_hash_lookup_big_state(hdev, ev->handle,
|
||||
BT_BOUND))) {
|
||||
if (ev->status) {
|
||||
hci_connect_cfm(conn, ev->status);
|
||||
hci_conn_del(conn);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hci_conn_set_handle(conn,
|
||||
__le16_to_cpu(ev->bis_handle[i++])))
|
||||
continue;
|
||||
|
||||
if (!ev->status) {
|
||||
conn->state = BT_CONNECTED;
|
||||
set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
|
||||
rcu_read_unlock();
|
||||
hci_debugfs_create_conn(conn);
|
||||
hci_conn_add_sysfs(conn);
|
||||
hci_iso_setup_path(conn);
|
||||
rcu_read_lock();
|
||||
continue;
|
||||
}
|
||||
|
||||
hci_connect_cfm(conn, ev->status);
|
||||
rcu_read_unlock();
|
||||
hci_conn_del(conn);
|
||||
rcu_read_lock();
|
||||
conn->state = BT_CONNECTED;
|
||||
set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
|
||||
hci_debugfs_create_conn(conn);
|
||||
hci_conn_add_sysfs(conn);
|
||||
hci_iso_setup_path(conn);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!ev->status && !i)
|
||||
/* If no BISes have been connected for the BIG,
|
||||
* terminate. This is in case all bound connections
|
||||
|
@ -1926,7 +1926,7 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||
}
|
||||
|
||||
static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
|
||||
sockptr_t optval, unsigned int len)
|
||||
sockptr_t optval, unsigned int optlen)
|
||||
{
|
||||
struct hci_ufilter uf = { .opcode = 0 };
|
||||
struct sock *sk = sock->sk;
|
||||
@ -1943,7 +1943,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
|
||||
|
||||
switch (optname) {
|
||||
case HCI_DATA_DIR:
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -1954,7 +1954,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
|
||||
case HCI_TIME_STAMP:
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -1974,7 +1974,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
|
||||
uf.event_mask[1] = *((u32 *) f->event_mask + 1);
|
||||
}
|
||||
|
||||
err = bt_copy_from_sockptr(&uf, sizeof(uf), optval, len);
|
||||
err = copy_safe_from_sockptr(&uf, sizeof(uf), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -2005,7 +2005,7 @@ static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
|
||||
}
|
||||
|
||||
static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
sockptr_t optval, unsigned int len)
|
||||
sockptr_t optval, unsigned int optlen)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
int err = 0;
|
||||
@ -2015,7 +2015,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
|
||||
if (level == SOL_HCI)
|
||||
return hci_sock_setsockopt_old(sock, level, optname, optval,
|
||||
len);
|
||||
optlen);
|
||||
|
||||
if (level != SOL_BLUETOOTH)
|
||||
return -ENOPROTOOPT;
|
||||
@ -2035,7 +2035,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, len);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
|
@ -1129,6 +1129,7 @@ static int iso_listen_bis(struct sock *sk)
|
||||
return -EHOSTUNREACH;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
lock_sock(sk);
|
||||
|
||||
/* Fail if user set invalid QoS */
|
||||
if (iso_pi(sk)->qos_user_set && !check_bcast_qos(&iso_pi(sk)->qos)) {
|
||||
@ -1158,10 +1159,10 @@ static int iso_listen_bis(struct sock *sk)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
hci_dev_put(hdev);
|
||||
|
||||
unlock:
|
||||
release_sock(sk);
|
||||
hci_dev_unlock(hdev);
|
||||
hci_dev_put(hdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1188,6 +1189,7 @@ static int iso_sock_listen(struct socket *sock, int backlog)
|
||||
|
||||
BT_DBG("sk %p backlog %d", sk, backlog);
|
||||
|
||||
sock_hold(sk);
|
||||
lock_sock(sk);
|
||||
|
||||
if (sk->sk_state != BT_BOUND) {
|
||||
@ -1200,10 +1202,16 @@ static int iso_sock_listen(struct socket *sock, int backlog)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!bacmp(&iso_pi(sk)->dst, BDADDR_ANY))
|
||||
if (!bacmp(&iso_pi(sk)->dst, BDADDR_ANY)) {
|
||||
err = iso_listen_cis(sk);
|
||||
else
|
||||
} else {
|
||||
/* Drop sock lock to avoid potential
|
||||
* deadlock with the hdev lock.
|
||||
*/
|
||||
release_sock(sk);
|
||||
err = iso_listen_bis(sk);
|
||||
lock_sock(sk);
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto done;
|
||||
@ -1215,6 +1223,7 @@ static int iso_sock_listen(struct socket *sock, int backlog)
|
||||
|
||||
done:
|
||||
release_sock(sk);
|
||||
sock_put(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1226,7 +1235,11 @@ static int iso_sock_accept(struct socket *sock, struct socket *newsock,
|
||||
long timeo;
|
||||
int err = 0;
|
||||
|
||||
lock_sock(sk);
|
||||
/* Use explicit nested locking to avoid lockdep warnings generated
|
||||
* because the parent socket and the child socket are locked on the
|
||||
* same thread.
|
||||
*/
|
||||
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
|
||||
|
||||
timeo = sock_rcvtimeo(sk, arg->flags & O_NONBLOCK);
|
||||
|
||||
@ -1257,7 +1270,7 @@ static int iso_sock_accept(struct socket *sock, struct socket *newsock,
|
||||
release_sock(sk);
|
||||
|
||||
timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
|
||||
lock_sock(sk);
|
||||
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
|
||||
}
|
||||
remove_wait_queue(sk_sleep(sk), &wait);
|
||||
|
||||
@ -1398,6 +1411,7 @@ static void iso_conn_big_sync(struct sock *sk)
|
||||
* change.
|
||||
*/
|
||||
hci_dev_lock(hdev);
|
||||
lock_sock(sk);
|
||||
|
||||
if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
|
||||
err = hci_le_big_create_sync(hdev, iso_pi(sk)->conn->hcon,
|
||||
@ -1410,6 +1424,7 @@ static void iso_conn_big_sync(struct sock *sk)
|
||||
err);
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
@ -1418,39 +1433,57 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct iso_pinfo *pi = iso_pi(sk);
|
||||
bool early_ret = false;
|
||||
int err = 0;
|
||||
|
||||
BT_DBG("sk %p", sk);
|
||||
|
||||
if (test_and_clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
|
||||
sock_hold(sk);
|
||||
lock_sock(sk);
|
||||
|
||||
switch (sk->sk_state) {
|
||||
case BT_CONNECT2:
|
||||
if (test_bit(BT_SK_PA_SYNC, &pi->flags)) {
|
||||
release_sock(sk);
|
||||
iso_conn_big_sync(sk);
|
||||
lock_sock(sk);
|
||||
|
||||
sk->sk_state = BT_LISTEN;
|
||||
} else {
|
||||
iso_conn_defer_accept(pi->conn->hcon);
|
||||
sk->sk_state = BT_CONFIG;
|
||||
}
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
|
||||
early_ret = true;
|
||||
break;
|
||||
case BT_CONNECTED:
|
||||
if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
|
||||
iso_conn_big_sync(sk);
|
||||
sk->sk_state = BT_LISTEN;
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
iso_conn_big_sync(sk);
|
||||
lock_sock(sk);
|
||||
|
||||
sk->sk_state = BT_LISTEN;
|
||||
early_ret = true;
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
break;
|
||||
case BT_CONNECT:
|
||||
release_sock(sk);
|
||||
return iso_connect_cis(sk);
|
||||
err = iso_connect_cis(sk);
|
||||
lock_sock(sk);
|
||||
|
||||
early_ret = true;
|
||||
break;
|
||||
default:
|
||||
release_sock(sk);
|
||||
break;
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
sock_put(sk);
|
||||
|
||||
if (early_ret)
|
||||
return err;
|
||||
}
|
||||
|
||||
return bt_sock_recvmsg(sock, msg, len, flags);
|
||||
@ -1566,7 +1599,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -1577,7 +1610,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
|
||||
case BT_PKT_STATUS:
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -1596,7 +1629,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
err = bt_copy_from_sockptr(&qos, sizeof(qos), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&qos, sizeof(qos), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -1617,8 +1650,8 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
err = bt_copy_from_sockptr(iso_pi(sk)->base, optlen, optval,
|
||||
optlen);
|
||||
err = copy_safe_from_sockptr(iso_pi(sk)->base, optlen, optval,
|
||||
optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -2118,6 +2151,11 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
return HCI_LM_ACCEPT;
|
||||
}
|
||||
|
||||
static bool iso_match(struct hci_conn *hcon)
|
||||
{
|
||||
return hcon->type == ISO_LINK || hcon->type == LE_LINK;
|
||||
}
|
||||
|
||||
static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
{
|
||||
if (hcon->type != ISO_LINK) {
|
||||
@ -2299,6 +2337,7 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
|
||||
static struct hci_cb iso_cb = {
|
||||
.name = "ISO",
|
||||
.match = iso_match,
|
||||
.connect_cfm = iso_connect_cfm,
|
||||
.disconn_cfm = iso_disconn_cfm,
|
||||
};
|
||||
|
@ -7217,6 +7217,11 @@ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool l2cap_match(struct hci_conn *hcon)
|
||||
{
|
||||
return hcon->type == ACL_LINK || hcon->type == LE_LINK;
|
||||
}
|
||||
|
||||
static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
|
||||
{
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
@ -7224,9 +7229,6 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
|
||||
struct l2cap_chan *pchan;
|
||||
u8 dst_type;
|
||||
|
||||
if (hcon->type != ACL_LINK && hcon->type != LE_LINK)
|
||||
return;
|
||||
|
||||
BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
|
||||
|
||||
if (status) {
|
||||
@ -7291,9 +7293,6 @@ int l2cap_disconn_ind(struct hci_conn *hcon)
|
||||
|
||||
static void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
|
||||
{
|
||||
if (hcon->type != ACL_LINK && hcon->type != LE_LINK)
|
||||
return;
|
||||
|
||||
BT_DBG("hcon %p reason %d", hcon, reason);
|
||||
|
||||
l2cap_conn_del(hcon, bt_to_errno(reason));
|
||||
@ -7572,6 +7571,7 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
|
||||
static struct hci_cb l2cap_cb = {
|
||||
.name = "L2CAP",
|
||||
.match = l2cap_match,
|
||||
.connect_cfm = l2cap_connect_cfm,
|
||||
.disconn_cfm = l2cap_disconn_cfm,
|
||||
.security_cfm = l2cap_security_cfm,
|
||||
|
@ -755,7 +755,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
|
||||
opts.max_tx = chan->max_tx;
|
||||
opts.txwin_size = chan->tx_win;
|
||||
|
||||
err = bt_copy_from_sockptr(&opts, sizeof(opts), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&opts, sizeof(opts), optval,
|
||||
optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -800,7 +801,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
|
||||
break;
|
||||
|
||||
case L2CAP_LM:
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -909,7 +910,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
|
||||
sec.level = BT_SECURITY_LOW;
|
||||
|
||||
err = bt_copy_from_sockptr(&sec, sizeof(sec), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -956,7 +957,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -970,7 +971,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
|
||||
case BT_FLUSHABLE:
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -1004,7 +1005,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
|
||||
pwr.force_active = BT_POWER_FORCE_ACTIVE_ON;
|
||||
|
||||
err = bt_copy_from_sockptr(&pwr, sizeof(pwr), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&pwr, sizeof(pwr), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -1015,7 +1016,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
|
||||
case BT_CHANNEL_POLICY:
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -1046,7 +1047,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
err = bt_copy_from_sockptr(&mtu, sizeof(mtu), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&mtu, sizeof(mtu), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -1076,7 +1077,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
err = bt_copy_from_sockptr(&mode, sizeof(mode), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&mode, sizeof(mode), optval,
|
||||
optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
|
@ -2134,6 +2134,11 @@ static int rfcomm_run(void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool rfcomm_match(struct hci_conn *hcon)
|
||||
{
|
||||
return hcon->type == ACL_LINK;
|
||||
}
|
||||
|
||||
static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
|
||||
{
|
||||
struct rfcomm_session *s;
|
||||
@ -2180,6 +2185,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
|
||||
|
||||
static struct hci_cb rfcomm_cb = {
|
||||
.name = "RFCOMM",
|
||||
.match = rfcomm_match,
|
||||
.security_cfm = rfcomm_security_cfm
|
||||
};
|
||||
|
||||
|
@ -629,10 +629,9 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname,
|
||||
|
||||
switch (optname) {
|
||||
case RFCOMM_LM:
|
||||
if (bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen)) {
|
||||
err = -EFAULT;
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
if (opt & RFCOMM_LM_FIPS) {
|
||||
err = -EINVAL;
|
||||
@ -685,7 +684,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
|
||||
sec.level = BT_SECURITY_LOW;
|
||||
|
||||
err = bt_copy_from_sockptr(&sec, sizeof(sec), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -703,7 +702,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
|
@ -319,10 +319,13 @@ static int sco_connect(struct sock *sk)
|
||||
else
|
||||
type = SCO_LINK;
|
||||
|
||||
if (sco_pi(sk)->setting == BT_VOICE_TRANSPARENT &&
|
||||
(!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev))) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto unlock;
|
||||
switch (sco_pi(sk)->setting & SCO_AIRMODE_MASK) {
|
||||
case SCO_AIRMODE_TRANSP:
|
||||
if (!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev)) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto unlock;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst,
|
||||
@ -896,7 +899,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -915,18 +918,11 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
|
||||
voice.setting = sco_pi(sk)->setting;
|
||||
|
||||
err = bt_copy_from_sockptr(&voice, sizeof(voice), optval,
|
||||
optlen);
|
||||
err = copy_safe_from_sockptr(&voice, sizeof(voice), optval,
|
||||
optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
/* Explicitly check for these values */
|
||||
if (voice.setting != BT_VOICE_TRANSPARENT &&
|
||||
voice.setting != BT_VOICE_CVSD_16BIT) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
sco_pi(sk)->setting = voice.setting;
|
||||
hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
|
||||
BDADDR_BREDR);
|
||||
@ -934,14 +930,19 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
err = -EBADFD;
|
||||
break;
|
||||
}
|
||||
if (enhanced_sync_conn_capable(hdev) &&
|
||||
voice.setting == BT_VOICE_TRANSPARENT)
|
||||
sco_pi(sk)->codec.id = BT_CODEC_TRANSPARENT;
|
||||
|
||||
switch (sco_pi(sk)->setting & SCO_AIRMODE_MASK) {
|
||||
case SCO_AIRMODE_TRANSP:
|
||||
if (enhanced_sync_conn_capable(hdev))
|
||||
sco_pi(sk)->codec.id = BT_CODEC_TRANSPARENT;
|
||||
break;
|
||||
}
|
||||
|
||||
hci_dev_put(hdev);
|
||||
break;
|
||||
|
||||
case BT_PKT_STATUS:
|
||||
err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -984,7 +985,8 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
err = bt_copy_from_sockptr(buffer, optlen, optval, optlen);
|
||||
err = copy_struct_from_sockptr(buffer, sizeof(buffer), optval,
|
||||
optlen);
|
||||
if (err) {
|
||||
hci_dev_put(hdev);
|
||||
break;
|
||||
@ -1396,11 +1398,13 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
return lm;
|
||||
}
|
||||
|
||||
static bool sco_match(struct hci_conn *hcon)
|
||||
{
|
||||
return hcon->type == SCO_LINK || hcon->type == ESCO_LINK;
|
||||
}
|
||||
|
||||
static void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
{
|
||||
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
|
||||
return;
|
||||
|
||||
BT_DBG("hcon %p bdaddr %pMR status %u", hcon, &hcon->dst, status);
|
||||
|
||||
if (!status) {
|
||||
@ -1415,9 +1419,6 @@ static void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
|
||||
static void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
|
||||
{
|
||||
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
|
||||
return;
|
||||
|
||||
BT_DBG("hcon %p reason %d", hcon, reason);
|
||||
|
||||
sco_conn_del(hcon, bt_to_errno(reason));
|
||||
@ -1443,6 +1444,7 @@ void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
|
||||
|
||||
static struct hci_cb sco_cb = {
|
||||
.name = "SCO",
|
||||
.match = sco_match,
|
||||
.connect_cfm = sco_connect_cfm,
|
||||
.disconn_cfm = sco_disconn_cfm,
|
||||
};
|
||||
|
@ -449,6 +449,21 @@ static struct net *net_alloc(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
static LLIST_HEAD(defer_free_list);
|
||||
|
||||
static void net_complete_free(void)
|
||||
{
|
||||
struct llist_node *kill_list;
|
||||
struct net *net, *next;
|
||||
|
||||
/* Get the list of namespaces to free from last round. */
|
||||
kill_list = llist_del_all(&defer_free_list);
|
||||
|
||||
llist_for_each_entry_safe(net, next, kill_list, defer_free_list)
|
||||
kmem_cache_free(net_cachep, net);
|
||||
|
||||
}
|
||||
|
||||
static void net_free(struct net *net)
|
||||
{
|
||||
if (refcount_dec_and_test(&net->passive)) {
|
||||
@ -457,7 +472,8 @@ static void net_free(struct net *net)
|
||||
/* There should not be any trackers left there. */
|
||||
ref_tracker_dir_exit(&net->notrefcnt_tracker);
|
||||
|
||||
kmem_cache_free(net_cachep, net);
|
||||
/* Wait for an extra rcu_barrier() before final free. */
|
||||
llist_add(&net->defer_free_list, &defer_free_list);
|
||||
}
|
||||
}
|
||||
|
||||
@ -642,6 +658,8 @@ static void cleanup_net(struct work_struct *work)
|
||||
*/
|
||||
rcu_barrier();
|
||||
|
||||
net_complete_free();
|
||||
|
||||
/* Finally it is safe to free my network namespace structure */
|
||||
list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
|
||||
list_del_init(&net->exit_list);
|
||||
|
@ -3972,8 +3972,10 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
|
||||
if (ops->peer_type) {
|
||||
peer_net = rtnl_get_peer_net(ops, data, extack);
|
||||
if (IS_ERR(peer_net))
|
||||
if (IS_ERR(peer_net)) {
|
||||
ret = PTR_ERR(peer_net);
|
||||
goto put_ops;
|
||||
}
|
||||
if (peer_net)
|
||||
rtnl_nets_add(&rtnl_nets, peer_net);
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
|
||||
static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
|
||||
struct net_device *netdev)
|
||||
{
|
||||
int src_port, switch_id;
|
||||
int src_port = -1, switch_id = -1;
|
||||
|
||||
dsa_8021q_rcv(skb, &src_port, &switch_id, NULL, NULL);
|
||||
|
||||
|
@ -61,15 +61,17 @@ int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
|
||||
err = -EACCES;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Update addresses before rehashing */
|
||||
inet->inet_daddr = fl4->daddr;
|
||||
inet->inet_dport = usin->sin_port;
|
||||
if (!inet->inet_saddr)
|
||||
inet->inet_saddr = fl4->saddr; /* Update source address */
|
||||
inet->inet_saddr = fl4->saddr;
|
||||
if (!inet->inet_rcv_saddr) {
|
||||
inet->inet_rcv_saddr = fl4->saddr;
|
||||
if (sk->sk_prot->rehash)
|
||||
sk->sk_prot->rehash(sk);
|
||||
}
|
||||
inet->inet_daddr = fl4->daddr;
|
||||
inet->inet_dport = usin->sin_port;
|
||||
reuseport_has_conns_set(sk);
|
||||
sk->sk_state = TCP_ESTABLISHED;
|
||||
sk_set_txhash(sk);
|
||||
|
@ -2478,7 +2478,8 @@ ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
||||
int our = 0;
|
||||
|
||||
if (!in_dev)
|
||||
return -EINVAL;
|
||||
return reason;
|
||||
|
||||
our = ip_check_mc_rcu(in_dev, daddr, saddr,
|
||||
ip_hdr(skb)->protocol);
|
||||
|
||||
|
@ -883,8 +883,10 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
|
||||
unsigned int size;
|
||||
|
||||
if (mptcp_syn_options(sk, skb, &size, &opts->mptcp)) {
|
||||
opts->options |= OPTION_MPTCP;
|
||||
remaining -= size;
|
||||
if (remaining >= size) {
|
||||
opts->options |= OPTION_MPTCP;
|
||||
remaining -= size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1088,13 +1088,13 @@ ieee80211_copy_mbssid_beacon(u8 *pos, struct cfg80211_mbssid_elems *dst,
|
||||
{
|
||||
int i, offset = 0;
|
||||
|
||||
dst->cnt = src->cnt;
|
||||
for (i = 0; i < src->cnt; i++) {
|
||||
memcpy(pos + offset, src->elem[i].data, src->elem[i].len);
|
||||
dst->elem[i].len = src->elem[i].len;
|
||||
dst->elem[i].data = pos + offset;
|
||||
offset += dst->elem[i].len;
|
||||
}
|
||||
dst->cnt = src->cnt;
|
||||
|
||||
return offset;
|
||||
}
|
||||
@ -1935,6 +1935,8 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
|
||||
params->eht_capa_len,
|
||||
link_sta);
|
||||
|
||||
ieee80211_sta_init_nss(link_sta);
|
||||
|
||||
if (params->opmode_notif_used) {
|
||||
/* returned value is only needed for rc update, but the
|
||||
* rc isn't initialized here yet, so ignore it
|
||||
@ -1944,8 +1946,6 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
|
||||
sband->band);
|
||||
}
|
||||
|
||||
ieee80211_sta_init_nss(link_sta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3726,13 +3726,12 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif, unsigned int link_id)
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_csa_finish);
|
||||
|
||||
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, bool block_tx)
|
||||
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
sdata->csa_blocked_queues = block_tx;
|
||||
sdata_info(sdata, "channel switch failed, disconnecting\n");
|
||||
wiphy_work_queue(local->hw.wiphy, &ifmgd->csa_connection_drop_work);
|
||||
}
|
||||
@ -5046,10 +5045,16 @@ static void ieee80211_del_intf_link(struct wiphy *wiphy,
|
||||
unsigned int link_id)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
u16 new_links = wdev->valid_links & ~BIT(link_id);
|
||||
|
||||
lockdep_assert_wiphy(sdata->local->hw.wiphy);
|
||||
|
||||
ieee80211_vif_set_links(sdata, wdev->valid_links, 0);
|
||||
/* During the link teardown process, certain functions require the
|
||||
* link_id to remain in the valid_links bitmap. Therefore, instead
|
||||
* of removing the link_id from the bitmap, pass a masked value to
|
||||
* simulate as if link_id does not exist anymore.
|
||||
*/
|
||||
ieee80211_vif_set_links(sdata, new_links, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1104,8 +1104,6 @@ struct ieee80211_sub_if_data {
|
||||
|
||||
unsigned long state;
|
||||
|
||||
bool csa_blocked_queues;
|
||||
|
||||
char name[IFNAMSIZ];
|
||||
|
||||
struct ieee80211_fragment_cache frags;
|
||||
@ -2412,17 +2410,13 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_hdr *hdr, bool ack, u16 tx_time);
|
||||
|
||||
unsigned int
|
||||
ieee80211_get_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
|
||||
unsigned long queues,
|
||||
enum queue_stop_reason reason,
|
||||
bool refcounted);
|
||||
void ieee80211_stop_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason);
|
||||
void ieee80211_wake_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason);
|
||||
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
|
||||
unsigned long queues,
|
||||
enum queue_stop_reason reason,
|
||||
@ -2433,6 +2427,43 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
enum queue_stop_reason reason,
|
||||
bool refcounted);
|
||||
static inline void
|
||||
ieee80211_stop_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_stop_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, true);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ieee80211_wake_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_wake_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, true);
|
||||
}
|
||||
static inline void
|
||||
ieee80211_stop_vif_queues_norefcount(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_stop_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, false);
|
||||
}
|
||||
static inline void
|
||||
ieee80211_wake_vif_queues_norefcount(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_wake_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, false);
|
||||
}
|
||||
void ieee80211_add_pending_skb(struct ieee80211_local *local,
|
||||
struct sk_buff *skb);
|
||||
void ieee80211_add_pending_skbs(struct ieee80211_local *local,
|
||||
|
@ -278,13 +278,8 @@ static int _ieee80211_change_mac(struct ieee80211_sub_if_data *sdata,
|
||||
ret = eth_mac_addr(sdata->dev, sa);
|
||||
|
||||
if (ret == 0) {
|
||||
if (check_dup) {
|
||||
memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
|
||||
ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
|
||||
} else {
|
||||
memset(sdata->vif.addr, 0, ETH_ALEN);
|
||||
memset(sdata->vif.bss_conf.addr, 0, ETH_ALEN);
|
||||
}
|
||||
memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
|
||||
ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
|
||||
}
|
||||
|
||||
/* Regardless of eth_mac_addr() return we still want to add the
|
||||
@ -1323,6 +1318,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
||||
}
|
||||
}
|
||||
|
||||
sdata->vif.addr_valid = sdata->vif.type != NL80211_IFTYPE_MONITOR ||
|
||||
(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE);
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
/* no need to tell driver, but set carrier and chanctx */
|
||||
@ -2374,18 +2371,14 @@ void ieee80211_vif_block_queues_csa(struct ieee80211_sub_if_data *sdata)
|
||||
if (ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA))
|
||||
return;
|
||||
|
||||
ieee80211_stop_vif_queues(local, sdata,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
sdata->csa_blocked_queues = true;
|
||||
ieee80211_stop_vif_queues_norefcount(local, sdata,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
}
|
||||
|
||||
void ieee80211_vif_unblock_queues_csa(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (sdata->csa_blocked_queues) {
|
||||
ieee80211_wake_vif_queues(local, sdata,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
sdata->csa_blocked_queues = false;
|
||||
}
|
||||
ieee80211_wake_vif_queues_norefcount(local, sdata,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
}
|
||||
|
@ -1157,14 +1157,14 @@ void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||
u64 changed)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
unsigned long bits = changed;
|
||||
unsigned long bits[] = { BITMAP_FROM_U64(changed) };
|
||||
u32 bit;
|
||||
|
||||
if (!bits)
|
||||
if (!changed)
|
||||
return;
|
||||
|
||||
/* if we race with running work, worst case this work becomes a noop */
|
||||
for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
|
||||
for_each_set_bit(bit, bits, sizeof(changed) * BITS_PER_BYTE)
|
||||
set_bit(bit, ifmsh->mbss_changed);
|
||||
set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
|
||||
wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
|
||||
|
@ -2638,8 +2638,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link,
|
||||
*/
|
||||
link->conf->csa_active = true;
|
||||
link->u.mgd.csa.blocked_tx = csa_ie.mode;
|
||||
sdata->csa_blocked_queues =
|
||||
csa_ie.mode && !ieee80211_hw_check(&local->hw, HANDLES_QUIET_CSA);
|
||||
|
||||
wiphy_work_queue(sdata->local->hw.wiphy,
|
||||
&ifmgd->csa_connection_drop_work);
|
||||
|
@ -657,7 +657,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_wake_queues);
|
||||
|
||||
static unsigned int
|
||||
unsigned int
|
||||
ieee80211_get_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
@ -669,7 +669,8 @@ ieee80211_get_vif_queues(struct ieee80211_local *local,
|
||||
queues = 0;
|
||||
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
queues |= BIT(sdata->vif.hw_queue[ac]);
|
||||
if (sdata->vif.hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
|
||||
queues |= BIT(sdata->vif.hw_queue[ac]);
|
||||
if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE)
|
||||
queues |= BIT(sdata->vif.cab_queue);
|
||||
} else {
|
||||
@ -724,24 +725,6 @@ void ieee80211_flush_queues(struct ieee80211_local *local,
|
||||
__ieee80211_flush_queues(local, sdata, 0, drop);
|
||||
}
|
||||
|
||||
void ieee80211_stop_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_stop_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, true);
|
||||
}
|
||||
|
||||
void ieee80211_wake_vif_queues(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum queue_stop_reason reason)
|
||||
{
|
||||
ieee80211_wake_queues_by_reason(&local->hw,
|
||||
ieee80211_get_vif_queues(local, sdata),
|
||||
reason, true);
|
||||
}
|
||||
|
||||
static void __iterate_interfaces(struct ieee80211_local *local,
|
||||
u32 iter_flags,
|
||||
void (*iterator)(void *data, u8 *mac,
|
||||
@ -1843,6 +1826,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
WARN(1, "Hardware became unavailable upon resume. This could be a software issue prior to suspend or a hardware issue.\n");
|
||||
else
|
||||
WARN(1, "Hardware became unavailable during restart.\n");
|
||||
ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
|
||||
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
|
||||
false);
|
||||
ieee80211_handle_reconfig_failure(local);
|
||||
return res;
|
||||
}
|
||||
|
@ -1596,7 +1596,6 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
|
||||
INIT_LIST_HEAD(&table->sets);
|
||||
INIT_LIST_HEAD(&table->objects);
|
||||
INIT_LIST_HEAD(&table->flowtables);
|
||||
write_pnet(&table->net, net);
|
||||
table->family = family;
|
||||
table->flags = flags;
|
||||
table->handle = ++nft_net->table_handle;
|
||||
@ -3987,8 +3986,11 @@ void nf_tables_rule_destroy(const struct nft_ctx *ctx, struct nft_rule *rule)
|
||||
kfree(rule);
|
||||
}
|
||||
|
||||
/* can only be used if rule is no longer visible to dumps */
|
||||
static void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule)
|
||||
{
|
||||
lockdep_commit_lock_is_held(ctx->net);
|
||||
|
||||
nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_RELEASE);
|
||||
nf_tables_rule_destroy(ctx, rule);
|
||||
}
|
||||
@ -5757,6 +5759,8 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
|
||||
struct nft_set_binding *binding,
|
||||
enum nft_trans_phase phase)
|
||||
{
|
||||
lockdep_commit_lock_is_held(ctx->net);
|
||||
|
||||
switch (phase) {
|
||||
case NFT_TRANS_PREPARE_ERROR:
|
||||
nft_set_trans_unbind(ctx, set);
|
||||
@ -11695,19 +11699,6 @@ static void __nft_release_basechain_now(struct nft_ctx *ctx)
|
||||
nf_tables_chain_destroy(ctx->chain);
|
||||
}
|
||||
|
||||
static void nft_release_basechain_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
|
||||
struct nft_ctx ctx = {
|
||||
.family = chain->table->family,
|
||||
.chain = chain,
|
||||
.net = read_pnet(&chain->table->net),
|
||||
};
|
||||
|
||||
__nft_release_basechain_now(&ctx);
|
||||
put_net(ctx.net);
|
||||
}
|
||||
|
||||
int __nft_release_basechain(struct nft_ctx *ctx)
|
||||
{
|
||||
struct nft_rule *rule;
|
||||
@ -11722,11 +11713,18 @@ int __nft_release_basechain(struct nft_ctx *ctx)
|
||||
nft_chain_del(ctx->chain);
|
||||
nft_use_dec(&ctx->table->use);
|
||||
|
||||
if (maybe_get_net(ctx->net))
|
||||
call_rcu(&ctx->chain->rcu_head, nft_release_basechain_rcu);
|
||||
else
|
||||
if (!maybe_get_net(ctx->net)) {
|
||||
__nft_release_basechain_now(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wait for ruleset dumps to complete. Owning chain is no longer in
|
||||
* lists, so new dumps can't find any of these rules anymore.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
|
||||
__nft_release_basechain_now(ctx);
|
||||
put_net(ctx->net);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__nft_release_basechain);
|
||||
|
@ -407,21 +407,23 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par)
|
||||
|
||||
mutex_lock(&list_mutex);
|
||||
|
||||
if (--info->timer->refcnt == 0) {
|
||||
pr_debug("deleting timer %s\n", info->label);
|
||||
|
||||
list_del(&info->timer->entry);
|
||||
timer_shutdown_sync(&info->timer->timer);
|
||||
cancel_work_sync(&info->timer->work);
|
||||
sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
|
||||
kfree(info->timer->attr.attr.name);
|
||||
kfree(info->timer);
|
||||
} else {
|
||||
if (--info->timer->refcnt > 0) {
|
||||
pr_debug("decreased refcnt of timer %s to %u\n",
|
||||
info->label, info->timer->refcnt);
|
||||
mutex_unlock(&list_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_debug("deleting timer %s\n", info->label);
|
||||
|
||||
list_del(&info->timer->entry);
|
||||
mutex_unlock(&list_mutex);
|
||||
|
||||
timer_shutdown_sync(&info->timer->timer);
|
||||
cancel_work_sync(&info->timer->work);
|
||||
sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
|
||||
kfree(info->timer->attr.attr.name);
|
||||
kfree(info->timer);
|
||||
}
|
||||
|
||||
static void idletimer_tg_destroy_v1(const struct xt_tgdtor_param *par)
|
||||
@ -432,25 +434,27 @@ static void idletimer_tg_destroy_v1(const struct xt_tgdtor_param *par)
|
||||
|
||||
mutex_lock(&list_mutex);
|
||||
|
||||
if (--info->timer->refcnt == 0) {
|
||||
pr_debug("deleting timer %s\n", info->label);
|
||||
|
||||
list_del(&info->timer->entry);
|
||||
if (info->timer->timer_type & XT_IDLETIMER_ALARM) {
|
||||
alarm_cancel(&info->timer->alarm);
|
||||
} else {
|
||||
timer_shutdown_sync(&info->timer->timer);
|
||||
}
|
||||
cancel_work_sync(&info->timer->work);
|
||||
sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
|
||||
kfree(info->timer->attr.attr.name);
|
||||
kfree(info->timer);
|
||||
} else {
|
||||
if (--info->timer->refcnt > 0) {
|
||||
pr_debug("decreased refcnt of timer %s to %u\n",
|
||||
info->label, info->timer->refcnt);
|
||||
mutex_unlock(&list_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_debug("deleting timer %s\n", info->label);
|
||||
|
||||
list_del(&info->timer->entry);
|
||||
mutex_unlock(&list_mutex);
|
||||
|
||||
if (info->timer->timer_type & XT_IDLETIMER_ALARM) {
|
||||
alarm_cancel(&info->timer->alarm);
|
||||
} else {
|
||||
timer_shutdown_sync(&info->timer->timer);
|
||||
}
|
||||
cancel_work_sync(&info->timer->work);
|
||||
sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
|
||||
kfree(info->timer->attr.attr.name);
|
||||
kfree(info->timer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,6 +79,8 @@ struct netem_sched_data {
|
||||
struct sk_buff *t_head;
|
||||
struct sk_buff *t_tail;
|
||||
|
||||
u32 t_len;
|
||||
|
||||
/* optional qdisc for classful handling (NULL at netem init) */
|
||||
struct Qdisc *qdisc;
|
||||
|
||||
@ -383,6 +385,7 @@ static void tfifo_reset(struct Qdisc *sch)
|
||||
rtnl_kfree_skbs(q->t_head, q->t_tail);
|
||||
q->t_head = NULL;
|
||||
q->t_tail = NULL;
|
||||
q->t_len = 0;
|
||||
}
|
||||
|
||||
static void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
|
||||
@ -412,6 +415,7 @@ static void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
|
||||
rb_link_node(&nskb->rbnode, parent, p);
|
||||
rb_insert_color(&nskb->rbnode, &q->t_root);
|
||||
}
|
||||
q->t_len++;
|
||||
sch->q.qlen++;
|
||||
}
|
||||
|
||||
@ -518,7 +522,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
||||
1<<get_random_u32_below(8);
|
||||
}
|
||||
|
||||
if (unlikely(sch->q.qlen >= sch->limit)) {
|
||||
if (unlikely(q->t_len >= sch->limit)) {
|
||||
/* re-link segs, so that qdisc_drop_all() frees them all */
|
||||
skb->next = segs;
|
||||
qdisc_drop_all(skb, sch, to_free);
|
||||
@ -702,8 +706,8 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
|
||||
tfifo_dequeue:
|
||||
skb = __qdisc_dequeue_head(&sch->q);
|
||||
if (skb) {
|
||||
qdisc_qstats_backlog_dec(sch, skb);
|
||||
deliver:
|
||||
qdisc_qstats_backlog_dec(sch, skb);
|
||||
qdisc_bstats_update(sch, skb);
|
||||
return skb;
|
||||
}
|
||||
@ -719,8 +723,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
|
||||
|
||||
if (time_to_send <= now && q->slot.slot_next <= now) {
|
||||
netem_erase_head(q, skb);
|
||||
sch->q.qlen--;
|
||||
qdisc_qstats_backlog_dec(sch, skb);
|
||||
q->t_len--;
|
||||
skb->next = NULL;
|
||||
skb->prev = NULL;
|
||||
/* skb->dev shares skb->rbnode area,
|
||||
@ -747,16 +750,21 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
|
||||
if (net_xmit_drop_count(err))
|
||||
qdisc_qstats_drop(sch);
|
||||
qdisc_tree_reduce_backlog(sch, 1, pkt_len);
|
||||
sch->qstats.backlog -= pkt_len;
|
||||
sch->q.qlen--;
|
||||
}
|
||||
goto tfifo_dequeue;
|
||||
}
|
||||
sch->q.qlen--;
|
||||
goto deliver;
|
||||
}
|
||||
|
||||
if (q->qdisc) {
|
||||
skb = q->qdisc->ops->dequeue(q->qdisc);
|
||||
if (skb)
|
||||
if (skb) {
|
||||
sch->q.qlen--;
|
||||
goto deliver;
|
||||
}
|
||||
}
|
||||
|
||||
qdisc_watchdog_schedule_ns(&q->watchdog,
|
||||
@ -766,8 +774,10 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
|
||||
|
||||
if (q->qdisc) {
|
||||
skb = q->qdisc->ops->dequeue(q->qdisc);
|
||||
if (skb)
|
||||
if (skb) {
|
||||
sch->q.qlen--;
|
||||
goto deliver;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -807,6 +807,7 @@ static void cleanup_bearer(struct work_struct *work)
|
||||
{
|
||||
struct udp_bearer *ub = container_of(work, struct udp_bearer, work);
|
||||
struct udp_replicast *rcast, *tmp;
|
||||
struct tipc_net *tn;
|
||||
|
||||
list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
|
||||
dst_cache_destroy(&rcast->dst_cache);
|
||||
@ -814,10 +815,14 @@ static void cleanup_bearer(struct work_struct *work)
|
||||
kfree_rcu(rcast, rcu);
|
||||
}
|
||||
|
||||
tn = tipc_net(sock_net(ub->ubsock->sk));
|
||||
|
||||
dst_cache_destroy(&ub->rcast.dst_cache);
|
||||
udp_tunnel_sock_release(ub->ubsock);
|
||||
|
||||
/* Note: could use a call_rcu() to avoid another synchronize_net() */
|
||||
synchronize_net();
|
||||
atomic_dec(&tipc_net(sock_net(ub->ubsock->sk))->wq_count);
|
||||
atomic_dec(&tn->wq_count);
|
||||
kfree(ub);
|
||||
}
|
||||
|
||||
|
@ -2313,6 +2313,7 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||
fds_sent = true;
|
||||
|
||||
if (unlikely(msg->msg_flags & MSG_SPLICE_PAGES)) {
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
err = skb_splice_from_iter(skb, &msg->msg_iter, size,
|
||||
sk->sk_allocation);
|
||||
if (err < 0) {
|
||||
|
@ -814,7 +814,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_MLO_LINKS] =
|
||||
NLA_POLICY_NESTED_ARRAY(nl80211_policy),
|
||||
[NL80211_ATTR_MLO_LINK_ID] =
|
||||
NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS),
|
||||
NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS - 1),
|
||||
[NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN),
|
||||
[NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT },
|
||||
|
@ -83,6 +83,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
|
||||
if (!request)
|
||||
return -ENOMEM;
|
||||
|
||||
request->n_channels = n_channels;
|
||||
if (wdev->conn->params.channel) {
|
||||
enum nl80211_band band = wdev->conn->params.channel->band;
|
||||
struct ieee80211_supported_band *sband =
|
||||
|
@ -2843,10 +2843,9 @@ void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id)
|
||||
break;
|
||||
}
|
||||
|
||||
wdev->valid_links &= ~BIT(link_id);
|
||||
|
||||
rdev_del_intf_link(rdev, wdev, link_id);
|
||||
|
||||
wdev->valid_links &= ~BIT(link_id);
|
||||
eth_zero_addr(wdev->links[link_id].addr);
|
||||
}
|
||||
|
||||
|
@ -22,20 +22,34 @@ SB_ITC=0
|
||||
h1_create()
|
||||
{
|
||||
simple_if_init $h1 192.0.1.1/24
|
||||
tc qdisc add dev $h1 clsact
|
||||
|
||||
# Add egress filter on $h1 that will guarantee that the packet sent,
|
||||
# will be the only packet being passed to the device.
|
||||
tc filter add dev $h1 egress pref 2 handle 102 matchall action drop
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
tc filter del dev $h1 egress pref 2 handle 102 matchall action drop
|
||||
tc qdisc del dev $h1 clsact
|
||||
simple_if_fini $h1 192.0.1.1/24
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
simple_if_init $h2 192.0.1.2/24
|
||||
tc qdisc add dev $h2 clsact
|
||||
|
||||
# Add egress filter on $h2 that will guarantee that the packet sent,
|
||||
# will be the only packet being passed to the device.
|
||||
tc filter add dev $h2 egress pref 1 handle 101 matchall action drop
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
tc filter del dev $h2 egress pref 1 handle 101 matchall action drop
|
||||
tc qdisc del dev $h2 clsact
|
||||
simple_if_fini $h2 192.0.1.2/24
|
||||
}
|
||||
|
||||
@ -101,6 +115,11 @@ port_pool_test()
|
||||
local exp_max_occ=$(devlink_cell_size_get)
|
||||
local max_occ
|
||||
|
||||
tc filter add dev $h1 egress protocol ip pref 1 handle 101 flower \
|
||||
src_mac $h1mac dst_mac $h2mac \
|
||||
src_ip 192.0.1.1 dst_ip 192.0.1.2 \
|
||||
action pass
|
||||
|
||||
devlink sb occupancy clearmax $DEVLINK_DEV
|
||||
|
||||
$MZ $h1 -c 1 -p 10 -a $h1mac -b $h2mac -A 192.0.1.1 -B 192.0.1.2 \
|
||||
@ -108,11 +127,6 @@ port_pool_test()
|
||||
|
||||
devlink sb occupancy snapshot $DEVLINK_DEV
|
||||
|
||||
RET=0
|
||||
max_occ=$(sb_occ_pool_check $dl_port1 $SB_POOL_ING $exp_max_occ)
|
||||
check_err $? "Expected iPool($SB_POOL_ING) max occupancy to be $exp_max_occ, but got $max_occ"
|
||||
log_test "physical port's($h1) ingress pool"
|
||||
|
||||
RET=0
|
||||
max_occ=$(sb_occ_pool_check $dl_port2 $SB_POOL_ING $exp_max_occ)
|
||||
check_err $? "Expected iPool($SB_POOL_ING) max occupancy to be $exp_max_occ, but got $max_occ"
|
||||
@ -122,6 +136,11 @@ port_pool_test()
|
||||
max_occ=$(sb_occ_pool_check $cpu_dl_port $SB_POOL_EGR_CPU $exp_max_occ)
|
||||
check_err $? "Expected ePool($SB_POOL_EGR_CPU) max occupancy to be $exp_max_occ, but got $max_occ"
|
||||
log_test "CPU port's egress pool"
|
||||
|
||||
tc filter del dev $h1 egress protocol ip pref 1 handle 101 flower \
|
||||
src_mac $h1mac dst_mac $h2mac \
|
||||
src_ip 192.0.1.1 dst_ip 192.0.1.2 \
|
||||
action pass
|
||||
}
|
||||
|
||||
port_tc_ip_test()
|
||||
@ -129,6 +148,11 @@ port_tc_ip_test()
|
||||
local exp_max_occ=$(devlink_cell_size_get)
|
||||
local max_occ
|
||||
|
||||
tc filter add dev $h1 egress protocol ip pref 1 handle 101 flower \
|
||||
src_mac $h1mac dst_mac $h2mac \
|
||||
src_ip 192.0.1.1 dst_ip 192.0.1.2 \
|
||||
action pass
|
||||
|
||||
devlink sb occupancy clearmax $DEVLINK_DEV
|
||||
|
||||
$MZ $h1 -c 1 -p 10 -a $h1mac -b $h2mac -A 192.0.1.1 -B 192.0.1.2 \
|
||||
@ -136,11 +160,6 @@ port_tc_ip_test()
|
||||
|
||||
devlink sb occupancy snapshot $DEVLINK_DEV
|
||||
|
||||
RET=0
|
||||
max_occ=$(sb_occ_itc_check $dl_port2 $SB_ITC $exp_max_occ)
|
||||
check_err $? "Expected ingress TC($SB_ITC) max occupancy to be $exp_max_occ, but got $max_occ"
|
||||
log_test "physical port's($h1) ingress TC - IP packet"
|
||||
|
||||
RET=0
|
||||
max_occ=$(sb_occ_itc_check $dl_port2 $SB_ITC $exp_max_occ)
|
||||
check_err $? "Expected ingress TC($SB_ITC) max occupancy to be $exp_max_occ, but got $max_occ"
|
||||
@ -150,6 +169,11 @@ port_tc_ip_test()
|
||||
max_occ=$(sb_occ_etc_check $cpu_dl_port $SB_ITC_CPU_IP $exp_max_occ)
|
||||
check_err $? "Expected egress TC($SB_ITC_CPU_IP) max occupancy to be $exp_max_occ, but got $max_occ"
|
||||
log_test "CPU port's egress TC - IP packet"
|
||||
|
||||
tc filter del dev $h1 egress protocol ip pref 1 handle 101 flower \
|
||||
src_mac $h1mac dst_mac $h2mac \
|
||||
src_ip 192.0.1.1 dst_ip 192.0.1.2 \
|
||||
action pass
|
||||
}
|
||||
|
||||
port_tc_arp_test()
|
||||
@ -157,17 +181,15 @@ port_tc_arp_test()
|
||||
local exp_max_occ=$(devlink_cell_size_get)
|
||||
local max_occ
|
||||
|
||||
tc filter add dev $h1 egress protocol arp pref 1 handle 101 flower \
|
||||
src_mac $h1mac action pass
|
||||
|
||||
devlink sb occupancy clearmax $DEVLINK_DEV
|
||||
|
||||
$MZ $h1 -c 1 -p 10 -a $h1mac -A 192.0.1.1 -t arp -q
|
||||
|
||||
devlink sb occupancy snapshot $DEVLINK_DEV
|
||||
|
||||
RET=0
|
||||
max_occ=$(sb_occ_itc_check $dl_port2 $SB_ITC $exp_max_occ)
|
||||
check_err $? "Expected ingress TC($SB_ITC) max occupancy to be $exp_max_occ, but got $max_occ"
|
||||
log_test "physical port's($h1) ingress TC - ARP packet"
|
||||
|
||||
RET=0
|
||||
max_occ=$(sb_occ_itc_check $dl_port2 $SB_ITC $exp_max_occ)
|
||||
check_err $? "Expected ingress TC($SB_ITC) max occupancy to be $exp_max_occ, but got $max_occ"
|
||||
@ -177,6 +199,9 @@ port_tc_arp_test()
|
||||
max_occ=$(sb_occ_etc_check $cpu_dl_port $SB_ITC_CPU_ARP $exp_max_occ)
|
||||
check_err $? "Expected egress TC($SB_ITC_IP2ME) max occupancy to be $exp_max_occ, but got $max_occ"
|
||||
log_test "CPU port's egress TC - ARP packet"
|
||||
|
||||
tc filter del dev $h1 egress protocol arp pref 1 handle 101 flower \
|
||||
src_mac $h1mac action pass
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
|
@ -61,9 +61,20 @@ ip -net "$ns2" a a 192.168.42.1/24 dev d0
|
||||
ip -net "$ns1" a a fec0:42::2/64 dev v0 nodad
|
||||
ip -net "$ns2" a a fec0:42::1/64 dev d0 nodad
|
||||
|
||||
# avoid neighbor lookups and enable martian IPv6 pings
|
||||
ns2_hwaddr=$(ip -net "$ns2" link show dev v0 | \
|
||||
sed -n 's, *link/ether \([^ ]*\) .*,\1,p')
|
||||
ns1_hwaddr=$(ip -net "$ns1" link show dev v0 | \
|
||||
sed -n 's, *link/ether \([^ ]*\) .*,\1,p')
|
||||
ip -net "$ns1" neigh add fec0:42::1 lladdr "$ns2_hwaddr" nud permanent dev v0
|
||||
ip -net "$ns1" neigh add fec0:23::1 lladdr "$ns2_hwaddr" nud permanent dev v0
|
||||
ip -net "$ns2" neigh add fec0:42::2 lladdr "$ns1_hwaddr" nud permanent dev d0
|
||||
ip -net "$ns2" neigh add fec0:23::2 lladdr "$ns1_hwaddr" nud permanent dev v0
|
||||
|
||||
# firewall matches to test
|
||||
[ -n "$iptables" ] && {
|
||||
common='-t raw -A PREROUTING -s 192.168.0.0/16'
|
||||
common+=' -p icmp --icmp-type echo-request'
|
||||
if ! ip netns exec "$ns2" "$iptables" $common -m rpfilter;then
|
||||
echo "Cannot add rpfilter rule"
|
||||
exit $ksft_skip
|
||||
@ -72,6 +83,7 @@ ip -net "$ns2" a a fec0:42::1/64 dev d0 nodad
|
||||
}
|
||||
[ -n "$ip6tables" ] && {
|
||||
common='-t raw -A PREROUTING -s fec0::/16'
|
||||
common+=' -p icmpv6 --icmpv6-type echo-request'
|
||||
if ! ip netns exec "$ns2" "$ip6tables" $common -m rpfilter;then
|
||||
echo "Cannot add rpfilter rule"
|
||||
exit $ksft_skip
|
||||
@ -82,8 +94,10 @@ ip -net "$ns2" a a fec0:42::1/64 dev d0 nodad
|
||||
table inet t {
|
||||
chain c {
|
||||
type filter hook prerouting priority raw;
|
||||
ip saddr 192.168.0.0/16 fib saddr . iif oif exists counter
|
||||
ip6 saddr fec0::/16 fib saddr . iif oif exists counter
|
||||
ip saddr 192.168.0.0/16 icmp type echo-request \
|
||||
fib saddr . iif oif exists counter
|
||||
ip6 saddr fec0::/16 icmpv6 type echo-request \
|
||||
fib saddr . iif oif exists counter
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
Loading…
Reference in New Issue
Block a user