aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml2
-rw-r--r--Documentation/devicetree/bindings/net/mdio-gpio.txt1
-rw-r--r--Documentation/devicetree/bindings/net/rockchip-dwmac.txt76
-rw-r--r--Documentation/devicetree/bindings/net/rockchip-dwmac.yaml120
-rw-r--r--Documentation/devicetree/bindings/net/snps,dwmac.yaml13
-rw-r--r--Documentation/networking/can.rst2
-rw-r--r--Documentation/networking/timestamping.rst63
-rw-r--r--MAINTAINERS1
-rw-r--r--arch/arm/boot/dts/uniphier-pxs2.dtsi2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3328.dtsi4
-rw-r--r--arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi2
-rw-r--r--arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi4
-rw-r--r--drivers/net/bonding/bond_main.c7
-rw-r--r--drivers/net/can/usb/etas_es58x/es58x_core.c4
-rw-r--r--drivers/net/can/usb/etas_es58x/es58x_core.h2
-rw-r--r--drivers/net/dsa/hirschmann/hellcreek_hwtstamp.c28
-rw-r--r--drivers/net/dsa/hirschmann/hellcreek_hwtstamp.h4
-rw-r--r--drivers/net/dsa/microchip/Kconfig10
-rw-r--r--drivers/net/dsa/microchip/Makefile1
-rw-r--r--drivers/net/dsa/microchip/ksz8.h69
-rw-r--r--drivers/net/dsa/microchip/ksz8795.c884
-rw-r--r--drivers/net/dsa/microchip/ksz8795_reg.h125
-rw-r--r--drivers/net/dsa/microchip/ksz8795_spi.c46
-rw-r--r--drivers/net/dsa/microchip/ksz8863_smi.c213
-rw-r--r--drivers/net/dsa/microchip/ksz_common.h3
-rw-r--r--drivers/net/dsa/mv88e6xxx/hwtstamp.c26
-rw-r--r--drivers/net/dsa/mv88e6xxx/hwtstamp.h10
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.c6
-rw-r--r--drivers/net/dsa/ocelot/felix.c19
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c2
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ptp.c16
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ptp.h4
-rw-r--r--drivers/net/ethernet/amd/pcnet32.c3
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c10
-rw-r--r--drivers/net/ethernet/davicom/dm9000.c1
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_main.c3
-rw-r--r--drivers/net/ethernet/mscc/ocelot.c83
-rw-r--r--drivers/net/ethernet/mscc/ocelot_net.c20
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_devlink.c1
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-mac.c4
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c35
-rw-r--r--drivers/net/ethernet/sfc/ef10.c3
-rw-r--r--drivers/net/ethernet/sfc/efx_channels.c2
-rw-r--r--drivers/net/ethernet/sfc/farch.c16
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c12
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c4
-rw-r--r--drivers/net/ethernet/xscale/ixp4xx_eth.c5
-rw-r--r--drivers/net/fddi/skfp/h/smc.h2
-rw-r--r--drivers/net/geneve.c4
-rw-r--r--drivers/net/macvlan.c45
-rw-r--r--drivers/net/mdio/mdio-bitbang.c8
-rw-r--r--drivers/net/mdio/mdio-gpio.c8
-rw-r--r--drivers/net/phy/intel-xway.c21
-rw-r--r--drivers/net/phy/marvell-88x2222.c2
-rw-r--r--drivers/net/phy/marvell.c52
-rw-r--r--drivers/net/usb/hso.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c7
-rw-r--r--include/linux/dsa/sja1105.h3
-rw-r--r--include/linux/mdio-bitbang.h3
-rw-r--r--include/linux/netfilter/nfnetlink.h33
-rw-r--r--include/linux/netfilter/x_tables.h16
-rw-r--r--include/linux/netfilter_arp/arp_tables.h8
-rw-r--r--include/linux/netfilter_bridge/ebtables.h9
-rw-r--r--include/linux/netfilter_ipv4/ip_tables.h11
-rw-r--r--include/linux/netfilter_ipv6/ip6_tables.h11
-rw-r--r--include/linux/socket.h2
-rw-r--r--include/net/addrconf.h1
-rw-r--r--include/net/dsa.h18
-rw-r--r--include/net/netfilter/ipv4/nf_defrag_ipv4.h3
-rw-r--r--include/net/netfilter/ipv6/nf_defrag_ipv6.h3
-rw-r--r--include/net/netfilter/nf_nat.h2
-rw-r--r--include/net/netfilter/nf_tables.h13
-rw-r--r--include/net/netns/ipv4.h10
-rw-r--r--include/net/netns/ipv6.h9
-rw-r--r--include/net/netns/x_tables.h8
-rw-r--r--include/soc/mscc/ocelot.h21
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h6
-rw-r--r--net/8021q/vlan.c3
-rw-r--r--net/8021q/vlan.h4
-rw-r--r--net/bridge/br_multicast.c33
-rw-r--r--net/bridge/netfilter/ebt_limit.c4
-rw-r--r--net/bridge/netfilter/ebt_mark.c4
-rw-r--r--net/bridge/netfilter/ebt_mark_m.c4
-rw-r--r--net/bridge/netfilter/ebtable_broute.c10
-rw-r--r--net/bridge/netfilter/ebtable_filter.c26
-rw-r--r--net/bridge/netfilter/ebtable_nat.c27
-rw-r--r--net/bridge/netfilter/ebtables.c54
-rw-r--r--net/can/proc.c6
-rw-r--r--net/core/dev.c8
-rw-r--r--net/core/neighbour.c4
-rw-r--r--net/dsa/Kconfig2
-rw-r--r--net/dsa/slave.c23
-rw-r--r--net/dsa/tag_ocelot.c27
-rw-r--r--net/dsa/tag_ocelot_8021q.c41
-rw-r--r--net/ipv4/netfilter/arp_tables.c73
-rw-r--r--net/ipv4/netfilter/arptable_filter.c17
-rw-r--r--net/ipv4/netfilter/ip_tables.c86
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c8
-rw-r--r--net/ipv4/netfilter/iptable_filter.c17
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c23
-rw-r--r--net/ipv4/netfilter/iptable_nat.c59
-rw-r--r--net/ipv4/netfilter/iptable_raw.c17
-rw-r--r--net/ipv4/netfilter/iptable_security.c17
-rw-r--r--net/ipv4/netfilter/nf_defrag_ipv4.c30
-rw-r--r--net/ipv6/mcast_snoop.c12
-rw-r--r--net/ipv6/netfilter/ip6_tables.c84
-rw-r--r--net/ipv6/netfilter/ip6table_filter.c17
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c24
-rw-r--r--net/ipv6/netfilter/ip6table_nat.c58
-rw-r--r--net/ipv6/netfilter/ip6table_raw.c17
-rw-r--r--net/ipv6/netfilter/ip6table_security.c17
-rw-r--r--net/ipv6/netfilter/nf_defrag_ipv6_hooks.c29
-rw-r--r--net/l2tp/l2tp_core.c10
-rw-r--r--net/llc/llc_station.c2
-rw-r--r--net/mpls/af_mpls.c1
-rw-r--r--net/mptcp/protocol.c25
-rw-r--r--net/netfilter/Kconfig10
-rw-r--r--net/netfilter/ipset/ip_set_core.c165
-rw-r--r--net/netfilter/nf_conntrack_netlink.c302
-rw-r--r--net/netfilter/nf_conntrack_proto.c8
-rw-r--r--net/netfilter/nf_log_syslog.c1
-rw-r--r--net/netfilter/nf_nat_core.c37
-rw-r--r--net/netfilter/nf_nat_proto.c38
-rw-r--r--net/netfilter/nf_tables_api.c1239
-rw-r--r--net/netfilter/nf_tables_offload.c10
-rw-r--r--net/netfilter/nfnetlink.c58
-rw-r--r--net/netfilter/nfnetlink_acct.c80
-rw-r--r--net/netfilter/nfnetlink_cthelper.c57
-rw-r--r--net/netfilter/nfnetlink_cttimeout.c146
-rw-r--r--net/netfilter/nfnetlink_log.c42
-rw-r--r--net/netfilter/nfnetlink_osf.c21
-rw-r--r--net/netfilter/nfnetlink_queue.c86
-rw-r--r--net/netfilter/nft_chain_filter.c5
-rw-r--r--net/netfilter/nft_compat.c33
-rw-r--r--net/netfilter/nft_dynset.c5
-rw-r--r--net/netfilter/nft_lookup.c12
-rw-r--r--net/netfilter/nft_objref.c11
-rw-r--r--net/netfilter/nft_set_hash.c6
-rw-r--r--net/netfilter/nft_set_pipapo.c6
-rw-r--r--net/netfilter/nft_set_rbtree.c6
-rw-r--r--net/netfilter/nft_socket.c49
-rw-r--r--net/netfilter/nft_tproxy.c24
-rw-r--r--net/netfilter/x_tables.c34
-rw-r--r--net/netfilter/xt_TPROXY.c13
-rw-r--r--net/netfilter/xt_limit.c6
-rw-r--r--net/netfilter/xt_socket.c14
-rw-r--r--net/nfc/digital_dep.c2
-rw-r--r--net/openvswitch/meter.c4
-rw-r--r--net/qrtr/mhi.c8
-rw-r--r--net/rds/ib_send.c1
-rw-r--r--net/rxrpc/rxkad.c2
-rw-r--r--net/sched/act_ct.c6
-rw-r--r--net/sched/sch_taprio.c6
-rw-r--r--net/smc/af_smc.c1
-rw-r--r--net/tls/tls_device.c2
-rw-r--r--net/vmw_vsock/virtio_transport_common.c28
-rw-r--r--net/vmw_vsock/vmci_transport.c3
157 files changed, 3621 insertions, 2201 deletions
diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
index 9f7d131bbcef..84985f53bffd 100644
--- a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
+++ b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
@@ -21,6 +21,8 @@ properties:
- microchip,ksz8765
- microchip,ksz8794
- microchip,ksz8795
+ - microchip,ksz8863
+ - microchip,ksz8873
- microchip,ksz9477
- microchip,ksz9897
- microchip,ksz9896
diff --git a/Documentation/devicetree/bindings/net/mdio-gpio.txt b/Documentation/devicetree/bindings/net/mdio-gpio.txt
index 8dbcf8295c6c..4d91a36c5cf5 100644
--- a/Documentation/devicetree/bindings/net/mdio-gpio.txt
+++ b/Documentation/devicetree/bindings/net/mdio-gpio.txt
@@ -2,6 +2,7 @@ MDIO on GPIOs
Currently defined compatibles:
- virtual,gpio-mdio
+- microchip,mdio-smi0
MDC and MDIO lines connected to GPIO controllers are listed in the
gpios property as described in section VIII.1 in the following order:
diff --git a/Documentation/devicetree/bindings/net/rockchip-dwmac.txt b/Documentation/devicetree/bindings/net/rockchip-dwmac.txt
deleted file mode 100644
index 3b71da7e8742..000000000000
--- a/Documentation/devicetree/bindings/net/rockchip-dwmac.txt
+++ /dev/null
@@ -1,76 +0,0 @@
-Rockchip SoC RK3288 10/100/1000 Ethernet driver(GMAC)
-
-The device node has following properties.
-
-Required properties:
- - compatible: should be "rockchip,<name>-gamc"
- "rockchip,px30-gmac": found on PX30 SoCs
- "rockchip,rk3128-gmac": found on RK312x SoCs
- "rockchip,rk3228-gmac": found on RK322x SoCs
- "rockchip,rk3288-gmac": found on RK3288 SoCs
- "rockchip,rk3328-gmac": found on RK3328 SoCs
- "rockchip,rk3366-gmac": found on RK3366 SoCs
- "rockchip,rk3368-gmac": found on RK3368 SoCs
- "rockchip,rk3399-gmac": found on RK3399 SoCs
- "rockchip,rv1108-gmac": found on RV1108 SoCs
- - reg: addresses and length of the register sets for the device.
- - interrupts: Should contain the GMAC interrupts.
- - interrupt-names: Should contain the interrupt names "macirq".
- - rockchip,grf: phandle to the syscon grf used to control speed and mode.
- - clocks: <&cru SCLK_MAC>: clock selector for main clock, from PLL or PHY.
- <&cru SCLK_MAC_PLL>: PLL clock for SCLK_MAC
- <&cru SCLK_MAC_RX>: clock gate for RX
- <&cru SCLK_MAC_TX>: clock gate for TX
- <&cru SCLK_MACREF>: clock gate for RMII referce clock
- <&cru SCLK_MACREF_OUT> clock gate for RMII reference clock output
- <&cru ACLK_GMAC>: AXI clock gate for GMAC
- <&cru PCLK_GMAC>: APB clock gate for GMAC
- - clock-names: One name for each entry in the clocks property.
- - phy-mode: See ethernet.txt file in the same directory.
- - pinctrl-names: Names corresponding to the numbered pinctrl states.
- - pinctrl-0: pin-control mode. can be <&rgmii_pins> or <&rmii_pins>.
- - clock_in_out: For RGMII, it must be "input", means main clock(125MHz)
- is not sourced from SoC's PLL, but input from PHY; For RMII, "input" means
- PHY provides the reference clock(50MHz), "output" means GMAC provides the
- reference clock.
- - snps,reset-gpio gpio number for phy reset.
- - snps,reset-active-low boolean flag to indicate if phy reset is active low.
- - assigned-clocks: main clock, should be <&cru SCLK_MAC>;
- - assigned-clock-parents = parent of main clock.
- can be <&ext_gmac> or <&cru SCLK_MAC_PLL>.
-
-Optional properties:
- - tx_delay: Delay value for TXD timing. Range value is 0~0x7F, 0x30 as default.
- - rx_delay: Delay value for RXD timing. Range value is 0~0x7F, 0x10 as default.
- - phy-supply: phandle to a regulator if the PHY needs one
-
-Example:
-
-gmac: ethernet@ff290000 {
- compatible = "rockchip,rk3288-gmac";
- reg = <0xff290000 0x10000>;
- interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "macirq";
- rockchip,grf = <&grf>;
- clocks = <&cru SCLK_MAC>,
- <&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>,
- <&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>,
- <&cru ACLK_GMAC>, <&cru PCLK_GMAC>;
- clock-names = "stmmaceth",
- "mac_clk_rx", "mac_clk_tx",
- "clk_mac_ref", "clk_mac_refout",
- "aclk_mac", "pclk_mac";
- phy-mode = "rgmii";
- pinctrl-names = "default";
- pinctrl-0 = <&rgmii_pins /*&rmii_pins*/>;
-
- clock_in_out = "input";
- snps,reset-gpio = <&gpio4 7 0>;
- snps,reset-active-low;
-
- assigned-clocks = <&cru SCLK_MAC>;
- assigned-clock-parents = <&ext_gmac>;
- tx_delay = <0x30>;
- rx_delay = <0x10>;
-
-};
diff --git a/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml
new file mode 100644
index 000000000000..5acddb6171bf
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml
@@ -0,0 +1,120 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/net/rockchip-dwmac.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Rockchip 10/100/1000 Ethernet driver(GMAC)
+
+maintainers:
+ - David Wu <[email protected]>
+
+# We need a select here so we don't match all nodes with 'snps,dwmac'
+select:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - rockchip,px30-gmac
+ - rockchip,rk3128-gmac
+ - rockchip,rk3228-gmac
+ - rockchip,rk3288-gmac
+ - rockchip,rk3328-gmac
+ - rockchip,rk3366-gmac
+ - rockchip,rk3368-gmac
+ - rockchip,rk3399-gmac
+ - rockchip,rv1108-gmac
+ required:
+ - compatible
+
+allOf:
+ - $ref: "snps,dwmac.yaml#"
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - rockchip,px30-gmac
+ - rockchip,rk3128-gmac
+ - rockchip,rk3228-gmac
+ - rockchip,rk3288-gmac
+ - rockchip,rk3328-gmac
+ - rockchip,rk3366-gmac
+ - rockchip,rk3368-gmac
+ - rockchip,rk3399-gmac
+ - rockchip,rv1108-gmac
+
+ clocks:
+ minItems: 5
+ maxItems: 8
+
+ clock-names:
+ contains:
+ enum:
+ - stmmaceth
+ - mac_clk_tx
+ - mac_clk_rx
+ - aclk_mac
+ - pclk_mac
+ - clk_mac_ref
+ - clk_mac_refout
+ - clk_mac_speed
+
+ clock_in_out:
+ description:
+ For RGMII, it must be "input", means main clock(125MHz)
+ is not sourced from SoC's PLL, but input from PHY.
+ For RMII, "input" means PHY provides the reference clock(50MHz),
+ "output" means GMAC provides the reference clock.
+ $ref: /schemas/types.yaml#/definitions/string
+ enum: [input, output]
+
+ rockchip,grf:
+ description: The phandle of the syscon node for the general register file.
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ tx_delay:
+ description: Delay value for TXD timing. Range value is 0~0x7F, 0x30 as default.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ rx_delay:
+ description: Delay value for RXD timing. Range value is 0~0x7F, 0x10 as default.
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ phy-supply:
+ description: PHY regulator
+
+required:
+ - compatible
+ - clocks
+ - clock-names
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/rk3288-cru.h>
+
+ gmac: ethernet@ff290000 {
+ compatible = "rockchip,rk3288-gmac";
+ reg = <0xff290000 0x10000>;
+ interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ clocks = <&cru SCLK_MAC>,
+ <&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>,
+ <&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>,
+ <&cru ACLK_GMAC>, <&cru PCLK_GMAC>;
+ clock-names = "stmmaceth",
+ "mac_clk_rx", "mac_clk_tx",
+ "clk_mac_ref", "clk_mac_refout",
+ "aclk_mac", "pclk_mac";
+ assigned-clocks = <&cru SCLK_MAC>;
+ assigned-clock-parents = <&ext_gmac>;
+
+ rockchip,grf = <&grf>;
+ phy-mode = "rgmii";
+ clock_in_out = "input";
+ tx_delay = <0x30>;
+ rx_delay = <0x10>;
+ };
diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
index 0642b0f59491..2edd8bea993e 100644
--- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml
+++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
@@ -56,6 +56,15 @@ properties:
- amlogic,meson8m2-dwmac
- amlogic,meson-gxbb-dwmac
- amlogic,meson-axg-dwmac
+ - rockchip,px30-gmac
+ - rockchip,rk3128-gmac
+ - rockchip,rk3228-gmac
+ - rockchip,rk3288-gmac
+ - rockchip,rk3328-gmac
+ - rockchip,rk3366-gmac
+ - rockchip,rk3368-gmac
+ - rockchip,rk3399-gmac
+ - rockchip,rv1108-gmac
- snps,dwmac
- snps,dwmac-3.50a
- snps,dwmac-3.610
@@ -89,7 +98,7 @@ properties:
clocks:
minItems: 1
- maxItems: 5
+ maxItems: 8
additionalItems: true
items:
- description: GMAC main clock
@@ -101,7 +110,7 @@ properties:
clock-names:
minItems: 1
- maxItems: 5
+ maxItems: 8
additionalItems: true
contains:
enum:
diff --git a/Documentation/networking/can.rst b/Documentation/networking/can.rst
index f8dae662e454..f34cb0e4460e 100644
--- a/Documentation/networking/can.rst
+++ b/Documentation/networking/can.rst
@@ -608,6 +608,8 @@ demand:
setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
&recv_own_msgs, sizeof(recv_own_msgs));
+Note that reception of a socket's own CAN frames are subject to the same
+filtering as other CAN frames (see :ref:`socketcan-rawfilter`).
.. _socketcan-rawfd:
diff --git a/Documentation/networking/timestamping.rst b/Documentation/networking/timestamping.rst
index f682e88fa87e..7db3985359bc 100644
--- a/Documentation/networking/timestamping.rst
+++ b/Documentation/networking/timestamping.rst
@@ -630,30 +630,45 @@ hardware timestamping on it. This is because the SO_TIMESTAMPING API does not
allow the delivery of multiple hardware timestamps for the same packet, so
anybody else except for the DSA switch port must be prevented from doing so.
-In code, DSA provides for most of the infrastructure for timestamping already,
-in generic code: a BPF classifier (``ptp_classify_raw``) is used to identify
-PTP event messages (any other packets, including PTP general messages, are not
-timestamped), and provides two hooks to drivers:
-
-- ``.port_txtstamp()``: The driver is passed a clone of the timestampable skb
- to be transmitted, before actually transmitting it. Typically, a switch will
- have a PTP TX timestamp register (or sometimes a FIFO) where the timestamp
- becomes available. There may be an IRQ that is raised upon this timestamp's
- availability, or the driver might have to poll after invoking
- ``dev_queue_xmit()`` towards the host interface. Either way, in the
- ``.port_txtstamp()`` method, the driver only needs to save the clone for
- later use (when the timestamp becomes available). Each skb is annotated with
- a pointer to its clone, in ``DSA_SKB_CB(skb)->clone``, to ease the driver's
- job of keeping track of which clone belongs to which skb.
-
-- ``.port_rxtstamp()``: The original (and only) timestampable skb is provided
- to the driver, for it to annotate it with a timestamp, if that is immediately
- available, or defer to later. On reception, timestamps might either be
- available in-band (through metadata in the DSA header, or attached in other
- ways to the packet), or out-of-band (through another RX timestamping FIFO).
- Deferral on RX is typically necessary when retrieving the timestamp needs a
- sleepable context. In that case, it is the responsibility of the DSA driver
- to call ``netif_rx_ni()`` on the freshly timestamped skb.
+In the generic layer, DSA provides the following infrastructure for PTP
+timestamping:
+
+- ``.port_txtstamp()``: a hook called prior to the transmission of
+ packets with a hardware TX timestamping request from user space.
+ This is required for two-step timestamping, since the hardware
+ timestamp becomes available after the actual MAC transmission, so the
+ driver must be prepared to correlate the timestamp with the original
+ packet so that it can re-enqueue the packet back into the socket's
+ error queue. To save the packet for when the timestamp becomes
+ available, the driver can call ``skb_clone_sk`` , save the clone pointer
+ in skb->cb and enqueue a tx skb queue. Typically, a switch will have a
+ PTP TX timestamp register (or sometimes a FIFO) where the timestamp
+ becomes available. In case of a FIFO, the hardware might store
+ key-value pairs of PTP sequence ID/message type/domain number and the
+ actual timestamp. To perform the correlation correctly between the
+ packets in a queue waiting for timestamping and the actual timestamps,
+ drivers can use a BPF classifier (``ptp_classify_raw``) to identify
+ the PTP transport type, and ``ptp_parse_header`` to interpret the PTP
+ header fields. There may be an IRQ that is raised upon this
+ timestamp's availability, or the driver might have to poll after
+ invoking ``dev_queue_xmit()`` towards the host interface.
+ One-step TX timestamping do not require packet cloning, since there is
+ no follow-up message required by the PTP protocol (because the
+ TX timestamp is embedded into the packet by the MAC), and therefore
+ user space does not expect the packet annotated with the TX timestamp
+ to be re-enqueued into its socket's error queue.
+
+- ``.port_rxtstamp()``: On RX, the BPF classifier is run by DSA to
+ identify PTP event messages (any other packets, including PTP general
+ messages, are not timestamped). The original (and only) timestampable
+ skb is provided to the driver, for it to annotate it with a timestamp,
+ if that is immediately available, or defer to later. On reception,
+ timestamps might either be available in-band (through metadata in the
+ DSA header, or attached in other ways to the packet), or out-of-band
+ (through another RX timestamping FIFO). Deferral on RX is typically
+ necessary when retrieving the timestamp needs a sleepable context. In
+ that case, it is the responsibility of the DSA driver to call
+ ``netif_rx_ni()`` on the freshly timestamped skb.
3.2.2 Ethernet PHYs
^^^^^^^^^^^^^^^^^^^
diff --git a/MAINTAINERS b/MAINTAINERS
index c3c8fa572580..0d85ae9e61e2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8532,7 +8532,6 @@ IBM Power SRIOV Virtual NIC Device Driver
M: Dany Madden <[email protected]>
M: Sukadev Bhattiprolu <[email protected]>
R: Thomas Falcon <[email protected]>
-R: Lijun Pan <[email protected]>
S: Supported
F: drivers/net/ethernet/ibm/ibmvnic.*
diff --git a/arch/arm/boot/dts/uniphier-pxs2.dtsi b/arch/arm/boot/dts/uniphier-pxs2.dtsi
index b0b15c97306b..e81e5937a60a 100644
--- a/arch/arm/boot/dts/uniphier-pxs2.dtsi
+++ b/arch/arm/boot/dts/uniphier-pxs2.dtsi
@@ -583,7 +583,7 @@
clocks = <&sys_clk 6>;
reset-names = "ether";
resets = <&sys_rst 6>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-id";
local-mac-address = [00 00 00 00 00 00];
socionext,syscon-phy-mode = <&soc_glue 0>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
index 063ed0adbec4..9709d659a5fc 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -919,8 +919,8 @@
"mac_clk_tx", "clk_mac_ref",
"aclk_mac", "pclk_mac",
"clk_macphy";
- resets = <&cru SRST_GMAC2PHY_A>, <&cru SRST_MACPHY>;
- reset-names = "stmmaceth", "mac-phy";
+ resets = <&cru SRST_GMAC2PHY_A>;
+ reset-names = "stmmaceth";
phy-mode = "rmii";
phy-handle = <&phy>;
snps,txpbl = <0x4>;
diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
index a87b8a678719..8f2c1c1e2c64 100644
--- a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
+++ b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi
@@ -734,7 +734,7 @@
clocks = <&sys_clk 6>;
reset-names = "ether";
resets = <&sys_rst 6>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-id";
local-mac-address = [00 00 00 00 00 00];
socionext,syscon-phy-mode = <&soc_glue 0>;
diff --git a/arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi b/arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi
index 0e52dadf54b3..be97da132258 100644
--- a/arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi
+++ b/arch/arm64/boot/dts/socionext/uniphier-pxs3.dtsi
@@ -564,7 +564,7 @@
clocks = <&sys_clk 6>;
reset-names = "ether";
resets = <&sys_rst 6>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-id";
local-mac-address = [00 00 00 00 00 00];
socionext,syscon-phy-mode = <&soc_glue 0>;
@@ -585,7 +585,7 @@
clocks = <&sys_clk 7>;
reset-names = "ether";
resets = <&sys_rst 7>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-id";
local-mac-address = [00 00 00 00 00 00];
socionext,syscon-phy-mode = <&soc_glue 1>;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index d5ca38aa8aa9..20bbda1b36e1 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4391,9 +4391,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
int agg_id = 0;
int ret = 0;
-#ifdef CONFIG_LOCKDEP
- WARN_ON(lockdep_is_held(&bond->mode_lock));
-#endif
+ might_sleep();
usable_slaves = kzalloc(struct_size(usable_slaves, arr,
bond->slave_cnt), GFP_KERNEL);
@@ -4406,7 +4404,9 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
struct ad_info ad_info;
+ spin_lock_bh(&bond->mode_lock);
if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
+ spin_unlock_bh(&bond->mode_lock);
pr_debug("bond_3ad_get_active_agg_info failed\n");
/* No active aggragator means it's not safe to use
* the previous array.
@@ -4414,6 +4414,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
bond_reset_slave_arr(bond);
goto out;
}
+ spin_unlock_bh(&bond->mode_lock);
agg_id = ad_info.aggregator_id;
}
bond_for_each_slave(bond, slave, iter) {
diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c
index 57e5f94468e9..8e9102482c52 100644
--- a/drivers/net/can/usb/etas_es58x/es58x_core.c
+++ b/drivers/net/can/usb/etas_es58x/es58x_core.c
@@ -688,7 +688,7 @@ int es58x_rx_err_msg(struct net_device *netdev, enum es58x_err error,
case ES58X_ERR_PROT_STUFF:
if (net_ratelimit())
- netdev_dbg(netdev, "Error BITSUFF\n");
+ netdev_dbg(netdev, "Error BITSTUFF\n");
if (cf)
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
@@ -1015,7 +1015,7 @@ int es58x_rx_cmd_ret_u32(struct net_device *netdev,
int ret;
netdev_warn(netdev,
- "%s: channel is already opened, closing and re-openning it to reflect new configuration\n",
+ "%s: channel is already opened, closing and re-opening it to reflect new configuration\n",
ret_desc);
ret = ops->disable_channel(es58x_priv(netdev));
if (ret)
diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.h b/drivers/net/can/usb/etas_es58x/es58x_core.h
index 5f4e7dc5be35..fcf219e727bf 100644
--- a/drivers/net/can/usb/etas_es58x/es58x_core.h
+++ b/drivers/net/can/usb/etas_es58x/es58x_core.h
@@ -625,7 +625,7 @@ static inline int es58x_get_netdev(struct es58x_device *es58x_dev,
return -ECHRNG;
*netdev = es58x_dev->netdev[channel_idx];
- if (!netdev || !netif_device_present(*netdev))
+ if (!*netdev || !netif_device_present(*netdev))
return -ENODEV;
return 0;
diff --git a/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.c b/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.c
index 69dd9a2e8bb6..40b41c794dfa 100644
--- a/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.c
+++ b/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.c
@@ -373,30 +373,38 @@ long hellcreek_hwtstamp_work(struct ptp_clock_info *ptp)
return restart ? 1 : -1;
}
-bool hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
- struct sk_buff *clone, unsigned int type)
+void hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb)
{
struct hellcreek *hellcreek = ds->priv;
struct hellcreek_port_hwtstamp *ps;
struct ptp_header *hdr;
+ struct sk_buff *clone;
+ unsigned int type;
ps = &hellcreek->ports[port].port_hwtstamp;
- /* Check if the driver is expected to do HW timestamping */
- if (!(skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP))
- return false;
+ type = ptp_classify_raw(skb);
+ if (type == PTP_CLASS_NONE)
+ return;
/* Make sure the message is a PTP message that needs to be timestamped
* and the interaction with the HW timestamping is enabled. If not, stop
* here
*/
- hdr = hellcreek_should_tstamp(hellcreek, port, clone, type);
+ hdr = hellcreek_should_tstamp(hellcreek, port, skb, type);
if (!hdr)
- return false;
+ return;
+
+ clone = skb_clone_sk(skb);
+ if (!clone)
+ return;
if (test_and_set_bit_lock(HELLCREEK_HWTSTAMP_TX_IN_PROGRESS,
- &ps->state))
- return false;
+ &ps->state)) {
+ kfree_skb(clone);
+ return;
+ }
ps->tx_skb = clone;
@@ -406,8 +414,6 @@ bool hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
ps->tx_tstamp_start = jiffies;
ptp_schedule_worker(hellcreek->ptp_clock, 0);
-
- return true;
}
bool hellcreek_port_rxtstamp(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.h b/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.h
index c0745ffa1ebb..71af77efb28b 100644
--- a/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.h
+++ b/drivers/net/dsa/hirschmann/hellcreek_hwtstamp.h
@@ -44,8 +44,8 @@ int hellcreek_port_hwtstamp_get(struct dsa_switch *ds, int port,
bool hellcreek_port_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type);
-bool hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
- struct sk_buff *clone, unsigned int type);
+void hellcreek_port_txtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb);
int hellcreek_get_ts_info(struct dsa_switch *ds, int port,
struct ethtool_ts_info *info);
diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
index 4ec6a47b7f72..c9e2a8989556 100644
--- a/drivers/net/dsa/microchip/Kconfig
+++ b/drivers/net/dsa/microchip/Kconfig
@@ -29,7 +29,7 @@ menuconfig NET_DSA_MICROCHIP_KSZ8795
depends on NET_DSA
select NET_DSA_MICROCHIP_KSZ_COMMON
help
- This driver adds support for Microchip KSZ8795 switch chips.
+ This driver adds support for Microchip KSZ8795/KSZ88X3 switch chips.
config NET_DSA_MICROCHIP_KSZ8795_SPI
tristate "KSZ8795 series SPI connected switch driver"
@@ -40,3 +40,11 @@ config NET_DSA_MICROCHIP_KSZ8795_SPI
It is required to use the KSZ8795 switch driver as the only access
is through SPI.
+
+config NET_DSA_MICROCHIP_KSZ8863_SMI
+ tristate "KSZ series SMI connected switch driver"
+ depends on NET_DSA_MICROCHIP_KSZ8795
+ select MDIO_BITBANG
+ help
+ Select to enable support for registering switches configured through
+ Microchip SMI. It supports the KSZ8863 and KSZ8873 switch.
diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile
index 929caa81e782..2a03b21a3386 100644
--- a/drivers/net/dsa/microchip/Makefile
+++ b/drivers/net/dsa/microchip/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C) += ksz9477_i2c.o
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI) += ksz9477_spi.o
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795) += ksz8795.o
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI) += ksz8795_spi.o
+obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI) += ksz8863_smi.o
diff --git a/drivers/net/dsa/microchip/ksz8.h b/drivers/net/dsa/microchip/ksz8.h
new file mode 100644
index 000000000000..9d611895d3cf
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz8.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Microchip KSZ8XXX series register access
+ *
+ * Copyright (C) 2020 Pengutronix, Michael Grzeschik <[email protected]>
+ */
+
+#ifndef __KSZ8XXX_H
+#define __KSZ8XXX_H
+#include <linux/kernel.h>
+
+enum ksz_regs {
+ REG_IND_CTRL_0,
+ REG_IND_DATA_8,
+ REG_IND_DATA_CHECK,
+ REG_IND_DATA_HI,
+ REG_IND_DATA_LO,
+ REG_IND_MIB_CHECK,
+ P_FORCE_CTRL,
+ P_LINK_STATUS,
+ P_LOCAL_CTRL,
+ P_NEG_RESTART_CTRL,
+ P_REMOTE_STATUS,
+ P_SPEED_STATUS,
+ S_TAIL_TAG_CTRL,
+};
+
+enum ksz_masks {
+ PORT_802_1P_REMAPPING,
+ SW_TAIL_TAG_ENABLE,
+ MIB_COUNTER_OVERFLOW,
+ MIB_COUNTER_VALID,
+ VLAN_TABLE_FID,
+ VLAN_TABLE_MEMBERSHIP,
+ VLAN_TABLE_VALID,
+ STATIC_MAC_TABLE_VALID,
+ STATIC_MAC_TABLE_USE_FID,
+ STATIC_MAC_TABLE_FID,
+ STATIC_MAC_TABLE_OVERRIDE,
+ STATIC_MAC_TABLE_FWD_PORTS,
+ DYNAMIC_MAC_TABLE_ENTRIES_H,
+ DYNAMIC_MAC_TABLE_MAC_EMPTY,
+ DYNAMIC_MAC_TABLE_NOT_READY,
+ DYNAMIC_MAC_TABLE_ENTRIES,
+ DYNAMIC_MAC_TABLE_FID,
+ DYNAMIC_MAC_TABLE_SRC_PORT,
+ DYNAMIC_MAC_TABLE_TIMESTAMP,
+};
+
+enum ksz_shifts {
+ VLAN_TABLE_MEMBERSHIP_S,
+ VLAN_TABLE,
+ STATIC_MAC_FWD_PORTS,
+ STATIC_MAC_FID,
+ DYNAMIC_MAC_ENTRIES_H,
+ DYNAMIC_MAC_ENTRIES,
+ DYNAMIC_MAC_FID,
+ DYNAMIC_MAC_TIMESTAMP,
+ DYNAMIC_MAC_SRC_PORT,
+};
+
+struct ksz8 {
+ const u8 *regs;
+ const u32 *masks;
+ const u8 *shifts;
+ void *priv;
+};
+
+#endif
diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c
index b4b7de63ca79..ad509a57a945 100644
--- a/drivers/net/dsa/microchip/ksz8795.c
+++ b/drivers/net/dsa/microchip/ksz8795.c
@@ -20,10 +20,112 @@
#include "ksz_common.h"
#include "ksz8795_reg.h"
+#include "ksz8.h"
+
+static const u8 ksz8795_regs[] = {
+ [REG_IND_CTRL_0] = 0x6E,
+ [REG_IND_DATA_8] = 0x70,
+ [REG_IND_DATA_CHECK] = 0x72,
+ [REG_IND_DATA_HI] = 0x71,
+ [REG_IND_DATA_LO] = 0x75,
+ [REG_IND_MIB_CHECK] = 0x74,
+ [P_FORCE_CTRL] = 0x0C,
+ [P_LINK_STATUS] = 0x0E,
+ [P_LOCAL_CTRL] = 0x07,
+ [P_NEG_RESTART_CTRL] = 0x0D,
+ [P_REMOTE_STATUS] = 0x08,
+ [P_SPEED_STATUS] = 0x09,
+ [S_TAIL_TAG_CTRL] = 0x0C,
+};
+
+static const u32 ksz8795_masks[] = {
+ [PORT_802_1P_REMAPPING] = BIT(7),
+ [SW_TAIL_TAG_ENABLE] = BIT(1),
+ [MIB_COUNTER_OVERFLOW] = BIT(6),
+ [MIB_COUNTER_VALID] = BIT(5),
+ [VLAN_TABLE_FID] = GENMASK(6, 0),
+ [VLAN_TABLE_MEMBERSHIP] = GENMASK(11, 7),
+ [VLAN_TABLE_VALID] = BIT(12),
+ [STATIC_MAC_TABLE_VALID] = BIT(21),
+ [STATIC_MAC_TABLE_USE_FID] = BIT(23),
+ [STATIC_MAC_TABLE_FID] = GENMASK(30, 24),
+ [STATIC_MAC_TABLE_OVERRIDE] = BIT(26),
+ [STATIC_MAC_TABLE_FWD_PORTS] = GENMASK(24, 20),
+ [DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(6, 0),
+ [DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(8),
+ [DYNAMIC_MAC_TABLE_NOT_READY] = BIT(7),
+ [DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 29),
+ [DYNAMIC_MAC_TABLE_FID] = GENMASK(26, 20),
+ [DYNAMIC_MAC_TABLE_SRC_PORT] = GENMASK(26, 24),
+ [DYNAMIC_MAC_TABLE_TIMESTAMP] = GENMASK(28, 27),
+};
+
+static const u8 ksz8795_shifts[] = {
+ [VLAN_TABLE_MEMBERSHIP_S] = 7,
+ [VLAN_TABLE] = 16,
+ [STATIC_MAC_FWD_PORTS] = 16,
+ [STATIC_MAC_FID] = 24,
+ [DYNAMIC_MAC_ENTRIES_H] = 3,
+ [DYNAMIC_MAC_ENTRIES] = 29,
+ [DYNAMIC_MAC_FID] = 16,
+ [DYNAMIC_MAC_TIMESTAMP] = 27,
+ [DYNAMIC_MAC_SRC_PORT] = 24,
+};
+
+static const u8 ksz8863_regs[] = {
+ [REG_IND_CTRL_0] = 0x79,
+ [REG_IND_DATA_8] = 0x7B,
+ [REG_IND_DATA_CHECK] = 0x7B,
+ [REG_IND_DATA_HI] = 0x7C,
+ [REG_IND_DATA_LO] = 0x80,
+ [REG_IND_MIB_CHECK] = 0x80,
+ [P_FORCE_CTRL] = 0x0C,
+ [P_LINK_STATUS] = 0x0E,
+ [P_LOCAL_CTRL] = 0x0C,
+ [P_NEG_RESTART_CTRL] = 0x0D,
+ [P_REMOTE_STATUS] = 0x0E,
+ [P_SPEED_STATUS] = 0x0F,
+ [S_TAIL_TAG_CTRL] = 0x03,
+};
+
+static const u32 ksz8863_masks[] = {
+ [PORT_802_1P_REMAPPING] = BIT(3),
+ [SW_TAIL_TAG_ENABLE] = BIT(6),
+ [MIB_COUNTER_OVERFLOW] = BIT(7),
+ [MIB_COUNTER_VALID] = BIT(6),
+ [VLAN_TABLE_FID] = GENMASK(15, 12),
+ [VLAN_TABLE_MEMBERSHIP] = GENMASK(18, 16),
+ [VLAN_TABLE_VALID] = BIT(19),
+ [STATIC_MAC_TABLE_VALID] = BIT(19),
+ [STATIC_MAC_TABLE_USE_FID] = BIT(21),
+ [STATIC_MAC_TABLE_FID] = GENMASK(29, 26),
+ [STATIC_MAC_TABLE_OVERRIDE] = BIT(20),
+ [STATIC_MAC_TABLE_FWD_PORTS] = GENMASK(18, 16),
+ [DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(5, 0),
+ [DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(7),
+ [DYNAMIC_MAC_TABLE_NOT_READY] = BIT(7),
+ [DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 28),
+ [DYNAMIC_MAC_TABLE_FID] = GENMASK(19, 16),
+ [DYNAMIC_MAC_TABLE_SRC_PORT] = GENMASK(21, 20),
+ [DYNAMIC_MAC_TABLE_TIMESTAMP] = GENMASK(23, 22),
+};
-static const struct {
+static u8 ksz8863_shifts[] = {
+ [VLAN_TABLE_MEMBERSHIP_S] = 16,
+ [STATIC_MAC_FWD_PORTS] = 16,
+ [STATIC_MAC_FID] = 22,
+ [DYNAMIC_MAC_ENTRIES_H] = 3,
+ [DYNAMIC_MAC_ENTRIES] = 24,
+ [DYNAMIC_MAC_FID] = 16,
+ [DYNAMIC_MAC_TIMESTAMP] = 24,
+ [DYNAMIC_MAC_SRC_PORT] = 20,
+};
+
+struct mib_names {
char string[ETH_GSTRING_LEN];
-} mib_names[] = {
+};
+
+static const struct mib_names ksz87xx_mib_names[] = {
{ "rx_hi" },
{ "rx_undersize" },
{ "rx_fragments" },
@@ -62,6 +164,48 @@ static const struct {
{ "tx_discards" },
};
+static const struct mib_names ksz88xx_mib_names[] = {
+ { "rx" },
+ { "rx_hi" },
+ { "rx_undersize" },
+ { "rx_fragments" },
+ { "rx_oversize" },
+ { "rx_jabbers" },
+ { "rx_symbol_err" },
+ { "rx_crc_err" },
+ { "rx_align_err" },
+ { "rx_mac_ctrl" },
+ { "rx_pause" },
+ { "rx_bcast" },
+ { "rx_mcast" },
+ { "rx_ucast" },
+ { "rx_64_or_less" },
+ { "rx_65_127" },
+ { "rx_128_255" },
+ { "rx_256_511" },
+ { "rx_512_1023" },
+ { "rx_1024_1522" },
+ { "tx" },
+ { "tx_hi" },
+ { "tx_late_col" },
+ { "tx_pause" },
+ { "tx_bcast" },
+ { "tx_mcast" },
+ { "tx_ucast" },
+ { "tx_deferred" },
+ { "tx_total_col" },
+ { "tx_exc_col" },
+ { "tx_single_col" },
+ { "tx_mult_col" },
+ { "rx_discards" },
+ { "tx_discards" },
+};
+
+static bool ksz_is_ksz88x3(struct ksz_device *dev)
+{
+ return dev->chip_id == 0x8830;
+}
+
static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
{
regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0);
@@ -74,12 +218,20 @@ static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
bits, set ? bits : 0);
}
-static int ksz8795_reset_switch(struct ksz_device *dev)
+static int ksz8_reset_switch(struct ksz_device *dev)
{
- /* reset switch */
- ksz_write8(dev, REG_POWER_MANAGEMENT_1,
- SW_SOFTWARE_POWER_DOWN << SW_POWER_MANAGEMENT_MODE_S);
- ksz_write8(dev, REG_POWER_MANAGEMENT_1, 0);
+ if (ksz_is_ksz88x3(dev)) {
+ /* reset switch */
+ ksz_cfg(dev, KSZ8863_REG_SW_RESET,
+ KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, true);
+ ksz_cfg(dev, KSZ8863_REG_SW_RESET,
+ KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, false);
+ } else {
+ /* reset switch */
+ ksz_write8(dev, REG_POWER_MANAGEMENT_1,
+ SW_SOFTWARE_POWER_DOWN << SW_POWER_MANAGEMENT_MODE_S);
+ ksz_write8(dev, REG_POWER_MANAGEMENT_1, 0);
+ }
return 0;
}
@@ -117,29 +269,34 @@ static void ksz8795_set_prio_queue(struct ksz_device *dev, int port, int queue)
true);
}
-static void ksz8795_r_mib_cnt(struct ksz_device *dev, int port, u16 addr,
- u64 *cnt)
+static void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
{
+ struct ksz8 *ksz8 = dev->priv;
+ const u32 *masks;
+ const u8 *regs;
u16 ctrl_addr;
u32 data;
u8 check;
int loop;
+ masks = ksz8->masks;
+ regs = ksz8->regs;
+
ctrl_addr = addr + dev->reg_mib_cnt * port;
ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
mutex_lock(&dev->alu_mutex);
- ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr);
+ ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
/* It is almost guaranteed to always read the valid bit because of
* slow SPI speed.
*/
for (loop = 2; loop > 0; loop--) {
- ksz_read8(dev, REG_IND_MIB_CHECK, &check);
+ ksz_read8(dev, regs[REG_IND_MIB_CHECK], &check);
- if (check & MIB_COUNTER_VALID) {
- ksz_read32(dev, REG_IND_DATA_LO, &data);
- if (check & MIB_COUNTER_OVERFLOW)
+ if (check & masks[MIB_COUNTER_VALID]) {
+ ksz_read32(dev, regs[REG_IND_DATA_LO], &data);
+ if (check & masks[MIB_COUNTER_OVERFLOW])
*cnt += MIB_COUNTER_VALUE + 1;
*cnt += data & MIB_COUNTER_VALUE;
break;
@@ -151,27 +308,33 @@ static void ksz8795_r_mib_cnt(struct ksz_device *dev, int port, u16 addr,
static void ksz8795_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
u64 *dropped, u64 *cnt)
{
+ struct ksz8 *ksz8 = dev->priv;
+ const u32 *masks;
+ const u8 *regs;
u16 ctrl_addr;
u32 data;
u8 check;
int loop;
+ masks = ksz8->masks;
+ regs = ksz8->regs;
+
addr -= dev->reg_mib_cnt;
- ctrl_addr = (KS_MIB_TOTAL_RX_1 - KS_MIB_TOTAL_RX_0) * port;
- ctrl_addr += addr + KS_MIB_TOTAL_RX_0;
+ ctrl_addr = (KSZ8795_MIB_TOTAL_RX_1 - KSZ8795_MIB_TOTAL_RX_0) * port;
+ ctrl_addr += addr + KSZ8795_MIB_TOTAL_RX_0;
ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
mutex_lock(&dev->alu_mutex);
- ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr);
+ ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
/* It is almost guaranteed to always read the valid bit because of
* slow SPI speed.
*/
for (loop = 2; loop > 0; loop--) {
- ksz_read8(dev, REG_IND_MIB_CHECK, &check);
+ ksz_read8(dev, regs[REG_IND_MIB_CHECK], &check);
- if (check & MIB_COUNTER_VALID) {
- ksz_read32(dev, REG_IND_DATA_LO, &data);
+ if (check & masks[MIB_COUNTER_VALID]) {
+ ksz_read32(dev, regs[REG_IND_DATA_LO], &data);
if (addr < 2) {
u64 total;
@@ -179,13 +342,13 @@ static void ksz8795_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
total <<= 32;
*cnt += total;
*cnt += data;
- if (check & MIB_COUNTER_OVERFLOW) {
+ if (check & masks[MIB_COUNTER_OVERFLOW]) {
total = MIB_TOTAL_BYTES_H + 1;
total <<= 32;
*cnt += total;
}
} else {
- if (check & MIB_COUNTER_OVERFLOW)
+ if (check & masks[MIB_COUNTER_OVERFLOW])
*cnt += MIB_PACKET_DROPPED + 1;
*cnt += data & MIB_PACKET_DROPPED;
}
@@ -195,8 +358,52 @@ static void ksz8795_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
mutex_unlock(&dev->alu_mutex);
}
-static void ksz8795_freeze_mib(struct ksz_device *dev, int port, bool freeze)
+static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
+ u64 *dropped, u64 *cnt)
+{
+ struct ksz8 *ksz8 = dev->priv;
+ const u8 *regs = ksz8->regs;
+ u32 *last = (u32 *)dropped;
+ u16 ctrl_addr;
+ u32 data;
+ u32 cur;
+
+ addr -= dev->reg_mib_cnt;
+ ctrl_addr = addr ? KSZ8863_MIB_PACKET_DROPPED_TX_0 :
+ KSZ8863_MIB_PACKET_DROPPED_RX_0;
+ ctrl_addr += port;
+ ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
+
+ mutex_lock(&dev->alu_mutex);
+ ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+ ksz_read32(dev, regs[REG_IND_DATA_LO], &data);
+ mutex_unlock(&dev->alu_mutex);
+
+ data &= MIB_PACKET_DROPPED;
+ cur = last[addr];
+ if (data != cur) {
+ last[addr] = data;
+ if (data < cur)
+ data += MIB_PACKET_DROPPED + 1;
+ data -= cur;
+ *cnt += data;
+ }
+}
+
+static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
+ u64 *dropped, u64 *cnt)
{
+ if (ksz_is_ksz88x3(dev))
+ ksz8863_r_mib_pkt(dev, port, addr, dropped, cnt);
+ else
+ ksz8795_r_mib_pkt(dev, port, addr, dropped, cnt);
+}
+
+static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
+{
+ if (ksz_is_ksz88x3(dev))
+ return;
+
/* enable the port for flush/freeze function */
if (freeze)
ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
@@ -207,14 +414,17 @@ static void ksz8795_freeze_mib(struct ksz_device *dev, int port, bool freeze)
ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
}
-static void ksz8795_port_init_cnt(struct ksz_device *dev, int port)
+static void ksz8_port_init_cnt(struct ksz_device *dev, int port)
{
struct ksz_port_mib *mib = &dev->ports[port].mib;
+ u64 *dropped;
- /* flush all enabled port MIB counters */
- ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
- ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FLUSH, true);
- ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
+ if (!ksz_is_ksz88x3(dev)) {
+ /* flush all enabled port MIB counters */
+ ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
+ ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FLUSH, true);
+ ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
+ }
mib->cnt_ptr = 0;
@@ -225,80 +435,99 @@ static void ksz8795_port_init_cnt(struct ksz_device *dev, int port)
++mib->cnt_ptr;
}
+ /* last one in storage */
+ dropped = &mib->counters[dev->mib_cnt];
+
/* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */
while (mib->cnt_ptr < dev->mib_cnt) {
dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr,
- NULL, &mib->counters[mib->cnt_ptr]);
+ dropped, &mib->counters[mib->cnt_ptr]);
++mib->cnt_ptr;
}
mib->cnt_ptr = 0;
memset(mib->counters, 0, dev->mib_cnt * sizeof(u64));
}
-static void ksz8795_r_table(struct ksz_device *dev, int table, u16 addr,
- u64 *data)
+static void ksz8_r_table(struct ksz_device *dev, int table, u16 addr, u64 *data)
{
+ struct ksz8 *ksz8 = dev->priv;
+ const u8 *regs = ksz8->regs;
u16 ctrl_addr;
ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr;
mutex_lock(&dev->alu_mutex);
- ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr);
- ksz_read64(dev, REG_IND_DATA_HI, data);
+ ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+ ksz_read64(dev, regs[REG_IND_DATA_HI], data);
mutex_unlock(&dev->alu_mutex);
}
-static void ksz8795_w_table(struct ksz_device *dev, int table, u16 addr,
- u64 data)
+static void ksz8_w_table(struct ksz_device *dev, int table, u16 addr, u64 data)
{
+ struct ksz8 *ksz8 = dev->priv;
+ const u8 *regs = ksz8->regs;
u16 ctrl_addr;
ctrl_addr = IND_ACC_TABLE(table) | addr;
mutex_lock(&dev->alu_mutex);
- ksz_write64(dev, REG_IND_DATA_HI, data);
- ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr);
+ ksz_write64(dev, regs[REG_IND_DATA_HI], data);
+ ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
mutex_unlock(&dev->alu_mutex);
}
-static int ksz8795_valid_dyn_entry(struct ksz_device *dev, u8 *data)
+static int ksz8_valid_dyn_entry(struct ksz_device *dev, u8 *data)
{
+ struct ksz8 *ksz8 = dev->priv;
int timeout = 100;
+ const u32 *masks;
+ const u8 *regs;
+
+ masks = ksz8->masks;
+ regs = ksz8->regs;
do {
- ksz_read8(dev, REG_IND_DATA_CHECK, data);
+ ksz_read8(dev, regs[REG_IND_DATA_CHECK], data);
timeout--;
- } while ((*data & DYNAMIC_MAC_TABLE_NOT_READY) && timeout);
+ } while ((*data & masks[DYNAMIC_MAC_TABLE_NOT_READY]) && timeout);
/* Entry is not ready for accessing. */
- if (*data & DYNAMIC_MAC_TABLE_NOT_READY) {
+ if (*data & masks[DYNAMIC_MAC_TABLE_NOT_READY]) {
return -EAGAIN;
/* Entry is ready for accessing. */
} else {
- ksz_read8(dev, REG_IND_DATA_8, data);
+ ksz_read8(dev, regs[REG_IND_DATA_8], data);
/* There is no valid entry in the table. */
- if (*data & DYNAMIC_MAC_TABLE_MAC_EMPTY)
+ if (*data & masks[DYNAMIC_MAC_TABLE_MAC_EMPTY])
return -ENXIO;
}
return 0;
}
-static int ksz8795_r_dyn_mac_table(struct ksz_device *dev, u16 addr,
- u8 *mac_addr, u8 *fid, u8 *src_port,
- u8 *timestamp, u16 *entries)
+static int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr,
+ u8 *mac_addr, u8 *fid, u8 *src_port,
+ u8 *timestamp, u16 *entries)
{
+ struct ksz8 *ksz8 = dev->priv;
u32 data_hi, data_lo;
+ const u8 *shifts;
+ const u32 *masks;
+ const u8 *regs;
u16 ctrl_addr;
u8 data;
int rc;
+ shifts = ksz8->shifts;
+ masks = ksz8->masks;
+ regs = ksz8->regs;
+
ctrl_addr = IND_ACC_TABLE(TABLE_DYNAMIC_MAC | TABLE_READ) | addr;
mutex_lock(&dev->alu_mutex);
- ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr);
+ ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
- rc = ksz8795_valid_dyn_entry(dev, &data);
+ rc = ksz8_valid_dyn_entry(dev, &data);
if (rc == -EAGAIN) {
if (addr == 0)
*entries = 0;
@@ -309,23 +538,23 @@ static int ksz8795_r_dyn_mac_table(struct ksz_device *dev, u16 addr,
u64 buf = 0;
int cnt;
- ksz_read64(dev, REG_IND_DATA_HI, &buf);
+ ksz_read64(dev, regs[REG_IND_DATA_HI], &buf);
data_hi = (u32)(buf >> 32);
data_lo = (u32)buf;
/* Check out how many valid entry in the table. */
- cnt = data & DYNAMIC_MAC_TABLE_ENTRIES_H;
- cnt <<= DYNAMIC_MAC_ENTRIES_H_S;
- cnt |= (data_hi & DYNAMIC_MAC_TABLE_ENTRIES) >>
- DYNAMIC_MAC_ENTRIES_S;
+ cnt = data & masks[DYNAMIC_MAC_TABLE_ENTRIES_H];
+ cnt <<= shifts[DYNAMIC_MAC_ENTRIES_H];
+ cnt |= (data_hi & masks[DYNAMIC_MAC_TABLE_ENTRIES]) >>
+ shifts[DYNAMIC_MAC_ENTRIES];
*entries = cnt + 1;
- *fid = (data_hi & DYNAMIC_MAC_TABLE_FID) >>
- DYNAMIC_MAC_FID_S;
- *src_port = (data_hi & DYNAMIC_MAC_TABLE_SRC_PORT) >>
- DYNAMIC_MAC_SRC_PORT_S;
- *timestamp = (data_hi & DYNAMIC_MAC_TABLE_TIMESTAMP) >>
- DYNAMIC_MAC_TIMESTAMP_S;
+ *fid = (data_hi & masks[DYNAMIC_MAC_TABLE_FID]) >>
+ shifts[DYNAMIC_MAC_FID];
+ *src_port = (data_hi & masks[DYNAMIC_MAC_TABLE_SRC_PORT]) >>
+ shifts[DYNAMIC_MAC_SRC_PORT];
+ *timestamp = (data_hi & masks[DYNAMIC_MAC_TABLE_TIMESTAMP]) >>
+ shifts[DYNAMIC_MAC_TIMESTAMP];
mac_addr[5] = (u8)data_lo;
mac_addr[4] = (u8)(data_lo >> 8);
@@ -341,91 +570,128 @@ static int ksz8795_r_dyn_mac_table(struct ksz_device *dev, u16 addr,
return rc;
}
-static int ksz8795_r_sta_mac_table(struct ksz_device *dev, u16 addr,
- struct alu_struct *alu)
+static int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
+ struct alu_struct *alu)
{
+ struct ksz8 *ksz8 = dev->priv;
u32 data_hi, data_lo;
+ const u8 *shifts;
+ const u32 *masks;
u64 data;
- ksz8795_r_table(dev, TABLE_STATIC_MAC, addr, &data);
+ shifts = ksz8->shifts;
+ masks = ksz8->masks;
+
+ ksz8_r_table(dev, TABLE_STATIC_MAC, addr, &data);
data_hi = data >> 32;
data_lo = (u32)data;
- if (data_hi & (STATIC_MAC_TABLE_VALID | STATIC_MAC_TABLE_OVERRIDE)) {
+ if (data_hi & (masks[STATIC_MAC_TABLE_VALID] |
+ masks[STATIC_MAC_TABLE_OVERRIDE])) {
alu->mac[5] = (u8)data_lo;
alu->mac[4] = (u8)(data_lo >> 8);
alu->mac[3] = (u8)(data_lo >> 16);
alu->mac[2] = (u8)(data_lo >> 24);
alu->mac[1] = (u8)data_hi;
alu->mac[0] = (u8)(data_hi >> 8);
- alu->port_forward = (data_hi & STATIC_MAC_TABLE_FWD_PORTS) >>
- STATIC_MAC_FWD_PORTS_S;
+ alu->port_forward =
+ (data_hi & masks[STATIC_MAC_TABLE_FWD_PORTS]) >>
+ shifts[STATIC_MAC_FWD_PORTS];
alu->is_override =
- (data_hi & STATIC_MAC_TABLE_OVERRIDE) ? 1 : 0;
+ (data_hi & masks[STATIC_MAC_TABLE_OVERRIDE]) ? 1 : 0;
data_hi >>= 1;
- alu->is_use_fid = (data_hi & STATIC_MAC_TABLE_USE_FID) ? 1 : 0;
- alu->fid = (data_hi & STATIC_MAC_TABLE_FID) >>
- STATIC_MAC_FID_S;
+ alu->is_static = true;
+ alu->is_use_fid =
+ (data_hi & masks[STATIC_MAC_TABLE_USE_FID]) ? 1 : 0;
+ alu->fid = (data_hi & masks[STATIC_MAC_TABLE_FID]) >>
+ shifts[STATIC_MAC_FID];
return 0;
}
return -ENXIO;
}
-static void ksz8795_w_sta_mac_table(struct ksz_device *dev, u16 addr,
- struct alu_struct *alu)
+static void ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr,
+ struct alu_struct *alu)
{
+ struct ksz8 *ksz8 = dev->priv;
u32 data_hi, data_lo;
+ const u8 *shifts;
+ const u32 *masks;
u64 data;
+ shifts = ksz8->shifts;
+ masks = ksz8->masks;
+
data_lo = ((u32)alu->mac[2] << 24) |
((u32)alu->mac[3] << 16) |
((u32)alu->mac[4] << 8) | alu->mac[5];
data_hi = ((u32)alu->mac[0] << 8) | alu->mac[1];
- data_hi |= (u32)alu->port_forward << STATIC_MAC_FWD_PORTS_S;
+ data_hi |= (u32)alu->port_forward << shifts[STATIC_MAC_FWD_PORTS];
if (alu->is_override)
- data_hi |= STATIC_MAC_TABLE_OVERRIDE;
+ data_hi |= masks[STATIC_MAC_TABLE_OVERRIDE];
if (alu->is_use_fid) {
- data_hi |= STATIC_MAC_TABLE_USE_FID;
- data_hi |= (u32)alu->fid << STATIC_MAC_FID_S;
+ data_hi |= masks[STATIC_MAC_TABLE_USE_FID];
+ data_hi |= (u32)alu->fid << shifts[STATIC_MAC_FID];
}
if (alu->is_static)
- data_hi |= STATIC_MAC_TABLE_VALID;
+ data_hi |= masks[STATIC_MAC_TABLE_VALID];
else
- data_hi &= ~STATIC_MAC_TABLE_OVERRIDE;
+ data_hi &= ~masks[STATIC_MAC_TABLE_OVERRIDE];
data = (u64)data_hi << 32 | data_lo;
- ksz8795_w_table(dev, TABLE_STATIC_MAC, addr, data);
+ ksz8_w_table(dev, TABLE_STATIC_MAC, addr, data);
}
-static void ksz8795_from_vlan(u16 vlan, u8 *fid, u8 *member, u8 *valid)
+static void ksz8_from_vlan(struct ksz_device *dev, u32 vlan, u8 *fid,
+ u8 *member, u8 *valid)
{
- *fid = vlan & VLAN_TABLE_FID;
- *member = (vlan & VLAN_TABLE_MEMBERSHIP) >> VLAN_TABLE_MEMBERSHIP_S;
- *valid = !!(vlan & VLAN_TABLE_VALID);
+ struct ksz8 *ksz8 = dev->priv;
+ const u8 *shifts;
+ const u32 *masks;
+
+ shifts = ksz8->shifts;
+ masks = ksz8->masks;
+
+ *fid = vlan & masks[VLAN_TABLE_FID];
+ *member = (vlan & masks[VLAN_TABLE_MEMBERSHIP]) >>
+ shifts[VLAN_TABLE_MEMBERSHIP_S];
+ *valid = !!(vlan & masks[VLAN_TABLE_VALID]);
}
-static void ksz8795_to_vlan(u8 fid, u8 member, u8 valid, u16 *vlan)
+static void ksz8_to_vlan(struct ksz_device *dev, u8 fid, u8 member, u8 valid,
+ u16 *vlan)
{
+ struct ksz8 *ksz8 = dev->priv;
+ const u8 *shifts;
+ const u32 *masks;
+
+ shifts = ksz8->shifts;
+ masks = ksz8->masks;
+
*vlan = fid;
- *vlan |= (u16)member << VLAN_TABLE_MEMBERSHIP_S;
+ *vlan |= (u16)member << shifts[VLAN_TABLE_MEMBERSHIP_S];
if (valid)
- *vlan |= VLAN_TABLE_VALID;
+ *vlan |= masks[VLAN_TABLE_VALID];
}
-static void ksz8795_r_vlan_entries(struct ksz_device *dev, u16 addr)
+static void ksz8_r_vlan_entries(struct ksz_device *dev, u16 addr)
{
+ struct ksz8 *ksz8 = dev->priv;
+ const u8 *shifts;
u64 data;
int i;
- ksz8795_r_table(dev, TABLE_VLAN, addr, &data);
+ shifts = ksz8->shifts;
+
+ ksz8_r_table(dev, TABLE_VLAN, addr, &data);
addr *= dev->phy_port_cnt;
for (i = 0; i < dev->phy_port_cnt; i++) {
dev->vlan_cache[addr + i].table[0] = (u16)data;
- data >>= VLAN_TABLE_S;
+ data >>= shifts[VLAN_TABLE];
}
}
-static void ksz8795_r_vlan_table(struct ksz_device *dev, u16 vid, u16 *vlan)
+static void ksz8_r_vlan_table(struct ksz_device *dev, u16 vid, u16 *vlan)
{
int index;
u16 *data;
@@ -435,11 +701,11 @@ static void ksz8795_r_vlan_table(struct ksz_device *dev, u16 vid, u16 *vlan)
data = (u16 *)&buf;
addr = vid / dev->phy_port_cnt;
index = vid & 3;
- ksz8795_r_table(dev, TABLE_VLAN, addr, &buf);
+ ksz8_r_table(dev, TABLE_VLAN, addr, &buf);
*vlan = data[index];
}
-static void ksz8795_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
+static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
{
int index;
u16 *data;
@@ -449,30 +715,37 @@ static void ksz8795_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
data = (u16 *)&buf;
addr = vid / dev->phy_port_cnt;
index = vid & 3;
- ksz8795_r_table(dev, TABLE_VLAN, addr, &buf);
+ ksz8_r_table(dev, TABLE_VLAN, addr, &buf);
data[index] = vlan;
dev->vlan_cache[vid].table[0] = vlan;
- ksz8795_w_table(dev, TABLE_VLAN, addr, buf);
+ ksz8_w_table(dev, TABLE_VLAN, addr, buf);
}
-static void ksz8795_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
+static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
{
+ struct ksz8 *ksz8 = dev->priv;
u8 restart, speed, ctrl, link;
+ const u8 *regs = ksz8->regs;
int processed = true;
u16 data = 0;
u8 p = phy;
switch (reg) {
case PHY_REG_CTRL:
- ksz_pread8(dev, p, P_NEG_RESTART_CTRL, &restart);
- ksz_pread8(dev, p, P_SPEED_STATUS, &speed);
- ksz_pread8(dev, p, P_FORCE_CTRL, &ctrl);
+ ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart);
+ ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed);
+ ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl);
if (restart & PORT_PHY_LOOPBACK)
data |= PHY_LOOPBACK;
if (ctrl & PORT_FORCE_100_MBIT)
data |= PHY_SPEED_100MBIT;
- if (!(ctrl & PORT_AUTO_NEG_DISABLE))
- data |= PHY_AUTO_NEG_ENABLE;
+ if (ksz_is_ksz88x3(dev)) {
+ if ((ctrl & PORT_AUTO_NEG_ENABLE))
+ data |= PHY_AUTO_NEG_ENABLE;
+ } else {
+ if (!(ctrl & PORT_AUTO_NEG_DISABLE))
+ data |= PHY_AUTO_NEG_ENABLE;
+ }
if (restart & PORT_POWER_DOWN)
data |= PHY_POWER_DOWN;
if (restart & PORT_AUTO_NEG_RESTART)
@@ -491,7 +764,7 @@ static void ksz8795_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
data |= PHY_LED_DISABLE;
break;
case PHY_REG_STATUS:
- ksz_pread8(dev, p, P_LINK_STATUS, &link);
+ ksz_pread8(dev, p, regs[P_LINK_STATUS], &link);
data = PHY_100BTX_FD_CAPABLE |
PHY_100BTX_CAPABLE |
PHY_10BT_FD_CAPABLE |
@@ -506,10 +779,13 @@ static void ksz8795_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
data = KSZ8795_ID_HI;
break;
case PHY_REG_ID_2:
- data = KSZ8795_ID_LO;
+ if (ksz_is_ksz88x3(dev))
+ data = KSZ8863_ID_LO;
+ else
+ data = KSZ8795_ID_LO;
break;
case PHY_REG_AUTO_NEGOTIATION:
- ksz_pread8(dev, p, P_LOCAL_CTRL, &ctrl);
+ ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
data = PHY_AUTO_NEG_802_3;
if (ctrl & PORT_AUTO_NEG_SYM_PAUSE)
data |= PHY_AUTO_NEG_SYM_PAUSE;
@@ -523,7 +799,7 @@ static void ksz8795_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
data |= PHY_AUTO_NEG_10BT;
break;
case PHY_REG_REMOTE_CAPABILITY:
- ksz_pread8(dev, p, P_REMOTE_STATUS, &link);
+ ksz_pread8(dev, p, regs[P_REMOTE_STATUS], &link);
data = PHY_AUTO_NEG_802_3;
if (link & PORT_REMOTE_SYM_PAUSE)
data |= PHY_AUTO_NEG_SYM_PAUSE;
@@ -546,10 +822,12 @@ static void ksz8795_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
*val = data;
}
-static void ksz8795_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
+static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
{
- u8 p = phy;
+ struct ksz8 *ksz8 = dev->priv;
u8 restart, speed, ctrl, data;
+ const u8 *regs = ksz8->regs;
+ u8 p = phy;
switch (reg) {
case PHY_REG_CTRL:
@@ -557,24 +835,32 @@ static void ksz8795_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
/* Do not support PHY reset function. */
if (val & PHY_RESET)
break;
- ksz_pread8(dev, p, P_SPEED_STATUS, &speed);
+ ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed);
data = speed;
if (val & PHY_HP_MDIX)
data |= PORT_HP_MDIX;
else
data &= ~PORT_HP_MDIX;
if (data != speed)
- ksz_pwrite8(dev, p, P_SPEED_STATUS, data);
- ksz_pread8(dev, p, P_FORCE_CTRL, &ctrl);
+ ksz_pwrite8(dev, p, regs[P_SPEED_STATUS], data);
+ ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl);
data = ctrl;
- if (!(val & PHY_AUTO_NEG_ENABLE))
- data |= PORT_AUTO_NEG_DISABLE;
- else
- data &= ~PORT_AUTO_NEG_DISABLE;
+ if (ksz_is_ksz88x3(dev)) {
+ if ((val & PHY_AUTO_NEG_ENABLE))
+ data |= PORT_AUTO_NEG_ENABLE;
+ else
+ data &= ~PORT_AUTO_NEG_ENABLE;
+ } else {
+ if (!(val & PHY_AUTO_NEG_ENABLE))
+ data |= PORT_AUTO_NEG_DISABLE;
+ else
+ data &= ~PORT_AUTO_NEG_DISABLE;
+
+ /* Fiber port does not support auto-negotiation. */
+ if (dev->ports[p].fiber)
+ data |= PORT_AUTO_NEG_DISABLE;
+ }
- /* Fiber port does not support auto-negotiation. */
- if (dev->ports[p].fiber)
- data |= PORT_AUTO_NEG_DISABLE;
if (val & PHY_SPEED_100MBIT)
data |= PORT_FORCE_100_MBIT;
else
@@ -584,8 +870,8 @@ static void ksz8795_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
else
data &= ~PORT_FORCE_FULL_DUPLEX;
if (data != ctrl)
- ksz_pwrite8(dev, p, P_FORCE_CTRL, data);
- ksz_pread8(dev, p, P_NEG_RESTART_CTRL, &restart);
+ ksz_pwrite8(dev, p, regs[P_FORCE_CTRL], data);
+ ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart);
data = restart;
if (val & PHY_LED_DISABLE)
data |= PORT_LED_OFF;
@@ -616,10 +902,10 @@ static void ksz8795_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
else
data &= ~PORT_PHY_LOOPBACK;
if (data != restart)
- ksz_pwrite8(dev, p, P_NEG_RESTART_CTRL, data);
+ ksz_pwrite8(dev, p, regs[P_NEG_RESTART_CTRL], data);
break;
case PHY_REG_AUTO_NEGOTIATION:
- ksz_pread8(dev, p, P_LOCAL_CTRL, &ctrl);
+ ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl);
data = ctrl;
data &= ~(PORT_AUTO_NEG_SYM_PAUSE |
PORT_AUTO_NEG_100BTX_FD |
@@ -637,34 +923,37 @@ static void ksz8795_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
if (val & PHY_AUTO_NEG_10BT)
data |= PORT_AUTO_NEG_10BT;
if (data != ctrl)
- ksz_pwrite8(dev, p, P_LOCAL_CTRL, data);
+ ksz_pwrite8(dev, p, regs[P_LOCAL_CTRL], data);
break;
default:
break;
}
}
-static enum dsa_tag_protocol ksz8795_get_tag_protocol(struct dsa_switch *ds,
- int port,
- enum dsa_tag_protocol mp)
+static enum dsa_tag_protocol ksz8_get_tag_protocol(struct dsa_switch *ds,
+ int port,
+ enum dsa_tag_protocol mp)
{
- return DSA_TAG_PROTO_KSZ8795;
+ struct ksz_device *dev = ds->priv;
+
+ /* ksz88x3 uses the same tag schema as KSZ9893 */
+ return ksz_is_ksz88x3(dev) ?
+ DSA_TAG_PROTO_KSZ9893 : DSA_TAG_PROTO_KSZ8795;
}
-static void ksz8795_get_strings(struct dsa_switch *ds, int port,
- u32 stringset, uint8_t *buf)
+static void ksz8_get_strings(struct dsa_switch *ds, int port,
+ u32 stringset, uint8_t *buf)
{
struct ksz_device *dev = ds->priv;
int i;
for (i = 0; i < dev->mib_cnt; i++) {
- memcpy(buf + i * ETH_GSTRING_LEN, mib_names[i].string,
- ETH_GSTRING_LEN);
+ memcpy(buf + i * ETH_GSTRING_LEN,
+ dev->mib_names[i].string, ETH_GSTRING_LEN);
}
}
-static void ksz8795_cfg_port_member(struct ksz_device *dev, int port,
- u8 member)
+static void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
{
u8 data;
@@ -675,8 +964,7 @@ static void ksz8795_cfg_port_member(struct ksz_device *dev, int port,
dev->ports[port].member = member;
}
-static void ksz8795_port_stp_state_set(struct dsa_switch *ds, int port,
- u8 state)
+static void ksz8_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
{
struct ksz_device *dev = ds->priv;
int forward = dev->member;
@@ -734,7 +1022,7 @@ static void ksz8795_port_stp_state_set(struct dsa_switch *ds, int port,
p->stp_state = state;
/* Port membership may share register with STP state. */
if (member >= 0 && member != p->member)
- ksz8795_cfg_port_member(dev, port, (u8)member);
+ ksz8_cfg_port_member(dev, port, (u8)member);
/* Check if forwarding needs to be updated. */
if (state != BR_STATE_FORWARDING) {
@@ -749,7 +1037,7 @@ static void ksz8795_port_stp_state_set(struct dsa_switch *ds, int port,
ksz_update_port_member(dev, port);
}
-static void ksz8795_flush_dyn_mac_table(struct ksz_device *dev, int port)
+static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
{
u8 learn[DSA_MAX_PORTS];
int first, index, cnt;
@@ -782,30 +1070,35 @@ static void ksz8795_flush_dyn_mac_table(struct ksz_device *dev, int port)
}
}
-static int ksz8795_port_vlan_filtering(struct dsa_switch *ds, int port,
- bool flag,
- struct netlink_ext_ack *extack)
+static int ksz8_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag,
+ struct netlink_ext_ack *extack)
{
struct ksz_device *dev = ds->priv;
+ if (ksz_is_ksz88x3(dev))
+ return -ENOTSUPP;
+
ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag);
return 0;
}
-static int ksz8795_port_vlan_add(struct dsa_switch *ds, int port,
- const struct switchdev_obj_port_vlan *vlan,
- struct netlink_ext_ack *extack)
+static int ksz8_port_vlan_add(struct dsa_switch *ds, int port,
+ const struct switchdev_obj_port_vlan *vlan,
+ struct netlink_ext_ack *extack)
{
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
struct ksz_device *dev = ds->priv;
u16 data, new_pvid = 0;
u8 fid, member, valid;
+ if (ksz_is_ksz88x3(dev))
+ return -ENOTSUPP;
+
ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged);
- ksz8795_r_vlan_table(dev, vlan->vid, &data);
- ksz8795_from_vlan(data, &fid, &member, &valid);
+ ksz8_r_vlan_table(dev, vlan->vid, &data);
+ ksz8_from_vlan(dev, data, &fid, &member, &valid);
/* First time to setup the VLAN entry. */
if (!valid) {
@@ -815,8 +1108,8 @@ static int ksz8795_port_vlan_add(struct dsa_switch *ds, int port,
}
member |= BIT(port);
- ksz8795_to_vlan(fid, member, valid, &data);
- ksz8795_w_vlan_table(dev, vlan->vid, data);
+ ksz8_to_vlan(dev, fid, member, valid, &data);
+ ksz8_w_vlan_table(dev, vlan->vid, data);
/* change PVID */
if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
@@ -834,21 +1127,24 @@ static int ksz8795_port_vlan_add(struct dsa_switch *ds, int port,
return 0;
}
-static int ksz8795_port_vlan_del(struct dsa_switch *ds, int port,
- const struct switchdev_obj_port_vlan *vlan)
+static int ksz8_port_vlan_del(struct dsa_switch *ds, int port,
+ const struct switchdev_obj_port_vlan *vlan)
{
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
struct ksz_device *dev = ds->priv;
u16 data, pvid, new_pvid = 0;
u8 fid, member, valid;
+ if (ksz_is_ksz88x3(dev))
+ return -ENOTSUPP;
+
ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid);
pvid = pvid & 0xFFF;
ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged);
- ksz8795_r_vlan_table(dev, vlan->vid, &data);
- ksz8795_from_vlan(data, &fid, &member, &valid);
+ ksz8_r_vlan_table(dev, vlan->vid, &data);
+ ksz8_from_vlan(dev, data, &fid, &member, &valid);
member &= ~BIT(port);
@@ -861,8 +1157,8 @@ static int ksz8795_port_vlan_del(struct dsa_switch *ds, int port,
if (pvid == vlan->vid)
new_pvid = 1;
- ksz8795_to_vlan(fid, member, valid, &data);
- ksz8795_w_vlan_table(dev, vlan->vid, data);
+ ksz8_to_vlan(dev, fid, member, valid, &data);
+ ksz8_w_vlan_table(dev, vlan->vid, data);
if (new_pvid != pvid)
ksz_pwrite16(dev, port, REG_PORT_CTRL_VID, pvid);
@@ -870,9 +1166,9 @@ static int ksz8795_port_vlan_del(struct dsa_switch *ds, int port,
return 0;
}
-static int ksz8795_port_mirror_add(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror,
- bool ingress)
+static int ksz8_port_mirror_add(struct dsa_switch *ds, int port,
+ struct dsa_mall_mirror_tc_entry *mirror,
+ bool ingress)
{
struct ksz_device *dev = ds->priv;
@@ -894,8 +1190,8 @@ static int ksz8795_port_mirror_add(struct dsa_switch *ds, int port,
return 0;
}
-static void ksz8795_port_mirror_del(struct dsa_switch *ds, int port,
- struct dsa_mall_mirror_tc_entry *mirror)
+static void ksz8_port_mirror_del(struct dsa_switch *ds, int port,
+ struct dsa_mall_mirror_tc_entry *mirror)
{
struct ksz_device *dev = ds->priv;
u8 data;
@@ -915,91 +1211,111 @@ static void ksz8795_port_mirror_del(struct dsa_switch *ds, int port,
PORT_MIRROR_SNIFFER, false);
}
-static void ksz8795_port_setup(struct ksz_device *dev, int port, bool cpu_port)
+static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port)
+{
+ struct ksz_port *p = &dev->ports[port];
+ u8 data8;
+
+ if (!p->interface && dev->compat_interface) {
+ dev_warn(dev->dev,
+ "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. "
+ "Please update your device tree.\n",
+ port);
+ p->interface = dev->compat_interface;
+ }
+
+ /* Configure MII interface for proper network communication. */
+ ksz_read8(dev, REG_PORT_5_CTRL_6, &data8);
+ data8 &= ~PORT_INTERFACE_TYPE;
+ data8 &= ~PORT_GMII_1GPS_MODE;
+ switch (p->interface) {
+ case PHY_INTERFACE_MODE_MII:
+ p->phydev.speed = SPEED_100;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ data8 |= PORT_INTERFACE_RMII;
+ p->phydev.speed = SPEED_100;
+ break;
+ case PHY_INTERFACE_MODE_GMII:
+ data8 |= PORT_GMII_1GPS_MODE;
+ data8 |= PORT_INTERFACE_GMII;
+ p->phydev.speed = SPEED_1000;
+ break;
+ default:
+ data8 &= ~PORT_RGMII_ID_IN_ENABLE;
+ data8 &= ~PORT_RGMII_ID_OUT_ENABLE;
+ if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ p->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+ data8 |= PORT_RGMII_ID_IN_ENABLE;
+ if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ p->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+ data8 |= PORT_RGMII_ID_OUT_ENABLE;
+ data8 |= PORT_GMII_1GPS_MODE;
+ data8 |= PORT_INTERFACE_RGMII;
+ p->phydev.speed = SPEED_1000;
+ break;
+ }
+ ksz_write8(dev, REG_PORT_5_CTRL_6, data8);
+ p->phydev.duplex = 1;
+}
+
+static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
{
struct ksz_port *p = &dev->ports[port];
- u8 data8, member;
+ struct ksz8 *ksz8 = dev->priv;
+ const u32 *masks;
+ u8 member;
+
+ masks = ksz8->masks;
/* enable broadcast storm limit */
ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true);
- ksz8795_set_prio_queue(dev, port, 4);
+ if (!ksz_is_ksz88x3(dev))
+ ksz8795_set_prio_queue(dev, port, 4);
/* disable DiffServ priority */
ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_ENABLE, false);
/* replace priority */
- ksz_port_cfg(dev, port, P_802_1P_CTRL, PORT_802_1P_REMAPPING, false);
+ ksz_port_cfg(dev, port, P_802_1P_CTRL,
+ masks[PORT_802_1P_REMAPPING], false);
/* enable 802.1p priority */
ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_ENABLE, true);
if (cpu_port) {
- if (!p->interface && dev->compat_interface) {
- dev_warn(dev->dev,
- "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. "
- "Please update your device tree.\n",
- port);
- p->interface = dev->compat_interface;
- }
-
- /* Configure MII interface for proper network communication. */
- ksz_read8(dev, REG_PORT_5_CTRL_6, &data8);
- data8 &= ~PORT_INTERFACE_TYPE;
- data8 &= ~PORT_GMII_1GPS_MODE;
- switch (p->interface) {
- case PHY_INTERFACE_MODE_MII:
- p->phydev.speed = SPEED_100;
- break;
- case PHY_INTERFACE_MODE_RMII:
- data8 |= PORT_INTERFACE_RMII;
- p->phydev.speed = SPEED_100;
- break;
- case PHY_INTERFACE_MODE_GMII:
- data8 |= PORT_GMII_1GPS_MODE;
- data8 |= PORT_INTERFACE_GMII;
- p->phydev.speed = SPEED_1000;
- break;
- default:
- data8 &= ~PORT_RGMII_ID_IN_ENABLE;
- data8 &= ~PORT_RGMII_ID_OUT_ENABLE;
- if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
- p->interface == PHY_INTERFACE_MODE_RGMII_RXID)
- data8 |= PORT_RGMII_ID_IN_ENABLE;
- if (p->interface == PHY_INTERFACE_MODE_RGMII_ID ||
- p->interface == PHY_INTERFACE_MODE_RGMII_TXID)
- data8 |= PORT_RGMII_ID_OUT_ENABLE;
- data8 |= PORT_GMII_1GPS_MODE;
- data8 |= PORT_INTERFACE_RGMII;
- p->phydev.speed = SPEED_1000;
- break;
- }
- ksz_write8(dev, REG_PORT_5_CTRL_6, data8);
- p->phydev.duplex = 1;
+ if (!ksz_is_ksz88x3(dev))
+ ksz8795_cpu_interface_select(dev, port);
member = dev->port_mask;
} else {
member = dev->host_mask | p->vid_member;
}
- ksz8795_cfg_port_member(dev, port, member);
+ ksz8_cfg_port_member(dev, port, member);
}
-static void ksz8795_config_cpu_port(struct dsa_switch *ds)
+static void ksz8_config_cpu_port(struct dsa_switch *ds)
{
struct ksz_device *dev = ds->priv;
+ struct ksz8 *ksz8 = dev->priv;
+ const u8 *regs = ksz8->regs;
struct ksz_port *p;
+ const u32 *masks;
u8 remote;
int i;
+ masks = ksz8->masks;
+
/* Switch marks the maximum frame with extra byte as oversize. */
ksz_cfg(dev, REG_SW_CTRL_2, SW_LEGAL_PACKET_DISABLE, true);
- ksz_cfg(dev, S_TAIL_TAG_CTRL, SW_TAIL_TAG_ENABLE, true);
+ ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true);
p = &dev->ports[dev->cpu_port];
p->vid_member = dev->port_mask;
p->on = 1;
- ksz8795_port_setup(dev, dev->cpu_port, true);
+ ksz8_port_setup(dev, dev->cpu_port, true);
dev->member = dev->host_mask;
for (i = 0; i < dev->phy_port_cnt; i++) {
@@ -1010,7 +1326,7 @@ static void ksz8795_config_cpu_port(struct dsa_switch *ds)
*/
p->vid_member = BIT(i);
p->member = dev->port_mask;
- ksz8795_port_stp_state_set(ds, i, BR_STATE_DISABLED);
+ ksz8_port_stp_state_set(ds, i, BR_STATE_DISABLED);
/* Last port may be disabled. */
if (i == dev->phy_port_cnt)
@@ -1022,9 +1338,11 @@ static void ksz8795_config_cpu_port(struct dsa_switch *ds)
p = &dev->ports[i];
if (!p->on)
continue;
- ksz_pread8(dev, i, P_REMOTE_STATUS, &remote);
- if (remote & PORT_FIBER_MODE)
- p->fiber = 1;
+ if (!ksz_is_ksz88x3(dev)) {
+ ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote);
+ if (remote & PORT_FIBER_MODE)
+ p->fiber = 1;
+ }
if (p->fiber)
ksz_port_cfg(dev, i, P_STP_CTRL, PORT_FORCE_FLOW_CTRL,
true);
@@ -1034,7 +1352,7 @@ static void ksz8795_config_cpu_port(struct dsa_switch *ds)
}
}
-static int ksz8795_setup(struct dsa_switch *ds)
+static int ksz8_setup(struct dsa_switch *ds)
{
struct ksz_device *dev = ds->priv;
struct alu_struct alu;
@@ -1045,7 +1363,7 @@ static int ksz8795_setup(struct dsa_switch *ds)
if (!dev->vlan_cache)
return -ENOMEM;
- ret = ksz8795_reset_switch(dev);
+ ret = ksz8_reset_switch(dev);
if (ret) {
dev_err(ds->dev, "failed to reset switch\n");
return ret;
@@ -1068,7 +1386,7 @@ static int ksz8795_setup(struct dsa_switch *ds)
UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP,
UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP);
- ksz8795_config_cpu_port(ds);
+ ksz8_config_cpu_port(ds);
ksz_cfg(dev, REG_SW_CTRL_2, MULTICAST_STORM_DISABLE, true);
@@ -1083,7 +1401,7 @@ static int ksz8795_setup(struct dsa_switch *ds)
BROADCAST_STORM_PROT_RATE) / 100);
for (i = 0; i < (dev->num_vlans / 4); i++)
- ksz8795_r_vlan_entries(dev, i);
+ ksz8_r_vlan_entries(dev, i);
/* Setup STP address for STP operation. */
memset(&alu, 0, sizeof(alu));
@@ -1092,7 +1410,7 @@ static int ksz8795_setup(struct dsa_switch *ds)
alu.is_override = true;
alu.port_forward = dev->host_mask;
- ksz8795_w_sta_mac_table(dev, 0, &alu);
+ ksz8_w_sta_mac_table(dev, 0, &alu);
ksz_init_mib_timer(dev);
@@ -1101,36 +1419,36 @@ static int ksz8795_setup(struct dsa_switch *ds)
return 0;
}
-static const struct dsa_switch_ops ksz8795_switch_ops = {
- .get_tag_protocol = ksz8795_get_tag_protocol,
- .setup = ksz8795_setup,
+static const struct dsa_switch_ops ksz8_switch_ops = {
+ .get_tag_protocol = ksz8_get_tag_protocol,
+ .setup = ksz8_setup,
.phy_read = ksz_phy_read16,
.phy_write = ksz_phy_write16,
.phylink_mac_link_down = ksz_mac_link_down,
.port_enable = ksz_enable_port,
- .get_strings = ksz8795_get_strings,
+ .get_strings = ksz8_get_strings,
.get_ethtool_stats = ksz_get_ethtool_stats,
.get_sset_count = ksz_sset_count,
.port_bridge_join = ksz_port_bridge_join,
.port_bridge_leave = ksz_port_bridge_leave,
- .port_stp_state_set = ksz8795_port_stp_state_set,
+ .port_stp_state_set = ksz8_port_stp_state_set,
.port_fast_age = ksz_port_fast_age,
- .port_vlan_filtering = ksz8795_port_vlan_filtering,
- .port_vlan_add = ksz8795_port_vlan_add,
- .port_vlan_del = ksz8795_port_vlan_del,
+ .port_vlan_filtering = ksz8_port_vlan_filtering,
+ .port_vlan_add = ksz8_port_vlan_add,
+ .port_vlan_del = ksz8_port_vlan_del,
.port_fdb_dump = ksz_port_fdb_dump,
.port_mdb_add = ksz_port_mdb_add,
.port_mdb_del = ksz_port_mdb_del,
- .port_mirror_add = ksz8795_port_mirror_add,
- .port_mirror_del = ksz8795_port_mirror_del,
+ .port_mirror_add = ksz8_port_mirror_add,
+ .port_mirror_del = ksz8_port_mirror_del,
};
-static u32 ksz8795_get_port_addr(int port, int offset)
+static u32 ksz8_get_port_addr(int port, int offset)
{
return PORT_CTRL_ADDR(port, offset);
}
-static int ksz8795_switch_detect(struct ksz_device *dev)
+static int ksz8_switch_detect(struct ksz_device *dev)
{
u8 id1, id2;
u16 id16;
@@ -1143,19 +1461,30 @@ static int ksz8795_switch_detect(struct ksz_device *dev)
id1 = id16 >> 8;
id2 = id16 & SW_CHIP_ID_M;
- if (id1 != FAMILY_ID ||
- (id2 != CHIP_ID_94 && id2 != CHIP_ID_95))
- return -ENODEV;
- if (id2 == CHIP_ID_95) {
- u8 val;
+ switch (id1) {
+ case KSZ87_FAMILY_ID:
+ if ((id2 != CHIP_ID_94 && id2 != CHIP_ID_95))
+ return -ENODEV;
+
+ if (id2 == CHIP_ID_95) {
+ u8 val;
- id2 = 0x95;
- ksz_read8(dev, REG_PORT_1_STATUS_0, &val);
- if (val & PORT_FIBER_MODE)
- id2 = 0x65;
- } else if (id2 == CHIP_ID_94) {
- id2 = 0x94;
+ id2 = 0x95;
+ ksz_read8(dev, REG_PORT_STATUS_0, &val);
+ if (val & PORT_FIBER_MODE)
+ id2 = 0x65;
+ } else if (id2 == CHIP_ID_94) {
+ id2 = 0x94;
+ }
+ break;
+ case KSZ88_FAMILY_ID:
+ if (id2 != CHIP_ID_63)
+ return -ENODEV;
+ break;
+ default:
+ dev_err(dev->dev, "invalid family id: %d\n", id1);
+ return -ENODEV;
}
id16 &= ~0xff;
id16 |= id2;
@@ -1174,7 +1503,7 @@ struct ksz_chip_data {
int port_cnt;
};
-static const struct ksz_chip_data ksz8795_switch_chips[] = {
+static const struct ksz_chip_data ksz8_switch_chips[] = {
{
.chip_id = 0x8795,
.dev_name = "KSZ8795",
@@ -1216,16 +1545,26 @@ static const struct ksz_chip_data ksz8795_switch_chips[] = {
.cpu_ports = 0x10, /* can be configured as cpu port */
.port_cnt = 5, /* total cpu and user ports */
},
+ {
+ .chip_id = 0x8830,
+ .dev_name = "KSZ8863/KSZ8873",
+ .num_vlans = 16,
+ .num_alus = 0,
+ .num_statics = 8,
+ .cpu_ports = 0x4, /* can be configured as cpu port */
+ .port_cnt = 3,
+ },
};
-static int ksz8795_switch_init(struct ksz_device *dev)
+static int ksz8_switch_init(struct ksz_device *dev)
{
+ struct ksz8 *ksz8 = dev->priv;
int i;
- dev->ds->ops = &ksz8795_switch_ops;
+ dev->ds->ops = &ksz8_switch_ops;
- for (i = 0; i < ARRAY_SIZE(ksz8795_switch_chips); i++) {
- const struct ksz_chip_data *chip = &ksz8795_switch_chips[i];
+ for (i = 0; i < ARRAY_SIZE(ksz8_switch_chips); i++) {
+ const struct ksz_chip_data *chip = &ksz8_switch_chips[i];
if (dev->chip_id == chip->chip_id) {
dev->name = chip->dev_name;
@@ -1247,8 +1586,21 @@ static int ksz8795_switch_init(struct ksz_device *dev)
if (!dev->cpu_ports)
return -ENODEV;
- dev->reg_mib_cnt = KSZ8795_COUNTER_NUM;
- dev->mib_cnt = ARRAY_SIZE(mib_names);
+ if (ksz_is_ksz88x3(dev)) {
+ ksz8->regs = ksz8863_regs;
+ ksz8->masks = ksz8863_masks;
+ ksz8->shifts = ksz8863_shifts;
+ dev->mib_cnt = ARRAY_SIZE(ksz88xx_mib_names);
+ dev->mib_names = ksz88xx_mib_names;
+ } else {
+ ksz8->regs = ksz8795_regs;
+ ksz8->masks = ksz8795_masks;
+ ksz8->shifts = ksz8795_shifts;
+ dev->mib_cnt = ARRAY_SIZE(ksz87xx_mib_names);
+ dev->mib_names = ksz87xx_mib_names;
+ }
+
+ dev->reg_mib_cnt = MIB_COUNTER_NUM;
dev->ports = devm_kzalloc(dev->dev,
dev->port_cnt * sizeof(struct ksz_port),
@@ -1272,36 +1624,36 @@ static int ksz8795_switch_init(struct ksz_device *dev)
return 0;
}
-static void ksz8795_switch_exit(struct ksz_device *dev)
+static void ksz8_switch_exit(struct ksz_device *dev)
{
- ksz8795_reset_switch(dev);
+ ksz8_reset_switch(dev);
}
-static const struct ksz_dev_ops ksz8795_dev_ops = {
- .get_port_addr = ksz8795_get_port_addr,
- .cfg_port_member = ksz8795_cfg_port_member,
- .flush_dyn_mac_table = ksz8795_flush_dyn_mac_table,
- .port_setup = ksz8795_port_setup,
- .r_phy = ksz8795_r_phy,
- .w_phy = ksz8795_w_phy,
- .r_dyn_mac_table = ksz8795_r_dyn_mac_table,
- .r_sta_mac_table = ksz8795_r_sta_mac_table,
- .w_sta_mac_table = ksz8795_w_sta_mac_table,
- .r_mib_cnt = ksz8795_r_mib_cnt,
- .r_mib_pkt = ksz8795_r_mib_pkt,
- .freeze_mib = ksz8795_freeze_mib,
- .port_init_cnt = ksz8795_port_init_cnt,
- .shutdown = ksz8795_reset_switch,
- .detect = ksz8795_switch_detect,
- .init = ksz8795_switch_init,
- .exit = ksz8795_switch_exit,
+static const struct ksz_dev_ops ksz8_dev_ops = {
+ .get_port_addr = ksz8_get_port_addr,
+ .cfg_port_member = ksz8_cfg_port_member,
+ .flush_dyn_mac_table = ksz8_flush_dyn_mac_table,
+ .port_setup = ksz8_port_setup,
+ .r_phy = ksz8_r_phy,
+ .w_phy = ksz8_w_phy,
+ .r_dyn_mac_table = ksz8_r_dyn_mac_table,
+ .r_sta_mac_table = ksz8_r_sta_mac_table,
+ .w_sta_mac_table = ksz8_w_sta_mac_table,
+ .r_mib_cnt = ksz8_r_mib_cnt,
+ .r_mib_pkt = ksz8_r_mib_pkt,
+ .freeze_mib = ksz8_freeze_mib,
+ .port_init_cnt = ksz8_port_init_cnt,
+ .shutdown = ksz8_reset_switch,
+ .detect = ksz8_switch_detect,
+ .init = ksz8_switch_init,
+ .exit = ksz8_switch_exit,
};
-int ksz8795_switch_register(struct ksz_device *dev)
+int ksz8_switch_register(struct ksz_device *dev)
{
- return ksz_switch_register(dev, &ksz8795_dev_ops);
+ return ksz_switch_register(dev, &ksz8_dev_ops);
}
-EXPORT_SYMBOL(ksz8795_switch_register);
+EXPORT_SYMBOL(ksz8_switch_register);
MODULE_AUTHOR("Tristram Ha <[email protected]>");
MODULE_DESCRIPTION("Microchip KSZ8795 Series Switch DSA Driver");
diff --git a/drivers/net/dsa/microchip/ksz8795_reg.h b/drivers/net/dsa/microchip/ksz8795_reg.h
index 40372047d40d..c2e52c40a54c 100644
--- a/drivers/net/dsa/microchip/ksz8795_reg.h
+++ b/drivers/net/dsa/microchip/ksz8795_reg.h
@@ -16,7 +16,8 @@
#define REG_CHIP_ID0 0x00
-#define FAMILY_ID 0x87
+#define KSZ87_FAMILY_ID 0x87
+#define KSZ88_FAMILY_ID 0x88
#define REG_CHIP_ID1 0x01
@@ -28,6 +29,12 @@
#define CHIP_ID_94 0x60
#define CHIP_ID_95 0x90
+#define CHIP_ID_63 0x30
+
+#define KSZ8863_REG_SW_RESET 0x43
+
+#define KSZ8863_GLOBAL_SOFTWARE_RESET BIT(4)
+#define KSZ8863_PCS_RESET BIT(0)
#define REG_SW_CTRL_0 0x02
@@ -98,7 +105,6 @@
#define REG_SW_CTRL_10 0x0C
-#define SW_TAIL_TAG_ENABLE BIT(1)
#define SW_PASS_PAUSE BIT(0)
#define REG_SW_CTRL_11 0x0D
@@ -150,7 +156,6 @@
#define REG_PORT_4_CTRL_2 0x42
#define REG_PORT_5_CTRL_2 0x52
-#define PORT_802_1P_REMAPPING BIT(7)
#define PORT_INGRESS_FILTER BIT(6)
#define PORT_DISCARD_NON_VID BIT(5)
#define PORT_FORCE_FLOW_CTRL BIT(4)
@@ -269,6 +274,7 @@
#define REG_PORT_3_CTRL_9 0x3C
#define REG_PORT_4_CTRL_9 0x4C
+#define PORT_AUTO_NEG_ENABLE BIT(7)
#define PORT_AUTO_NEG_DISABLE BIT(7)
#define PORT_FORCE_100_MBIT BIT(6)
#define PORT_FORCE_FULL_DUPLEX BIT(5)
@@ -319,14 +325,12 @@
#define REG_PORT_CTRL_5 0x05
-#define REG_PORT_CTRL_7 0x07
#define REG_PORT_STATUS_0 0x08
#define REG_PORT_STATUS_1 0x09
#define REG_PORT_LINK_MD_CTRL 0x0A
#define REG_PORT_LINK_MD_RESULT 0x0B
#define REG_PORT_CTRL_9 0x0C
#define REG_PORT_CTRL_10 0x0D
-#define REG_PORT_STATUS_2 0x0E
#define REG_PORT_STATUS_3 0x0F
#define REG_PORT_CTRL_12 0xA0
@@ -356,8 +360,6 @@
#define REG_SW_MAC_ADDR_4 0x6C
#define REG_SW_MAC_ADDR_5 0x6D
-#define REG_IND_CTRL_0 0x6E
-
#define TABLE_EXT_SELECT_S 5
#define TABLE_EEE_V 1
#define TABLE_ACL_V 2
@@ -383,23 +385,13 @@
#define TABLE_ENTRY_MASK 0x03FF
#define TABLE_EXT_ENTRY_MASK 0x0FFF
-#define REG_IND_DATA_8 0x70
-#define REG_IND_DATA_7 0x71
-#define REG_IND_DATA_6 0x72
#define REG_IND_DATA_5 0x73
-#define REG_IND_DATA_4 0x74
-#define REG_IND_DATA_3 0x75
#define REG_IND_DATA_2 0x76
#define REG_IND_DATA_1 0x77
#define REG_IND_DATA_0 0x78
#define REG_IND_DATA_PME_EEE_ACL 0xA0
-#define REG_IND_DATA_CHECK REG_IND_DATA_6
-#define REG_IND_MIB_CHECK REG_IND_DATA_4
-#define REG_IND_DATA_HI REG_IND_DATA_7
-#define REG_IND_DATA_LO REG_IND_DATA_3
-
#define REG_INT_STATUS 0x7C
#define REG_INT_ENABLE 0x7D
@@ -816,6 +808,7 @@
#define KSZ8795_ID_HI 0x0022
#define KSZ8795_ID_LO 0x1550
+#define KSZ8863_ID_LO 0x1430
#define KSZ8795_SW_ID 0x8795
@@ -846,7 +839,7 @@
#define KS_PRIO_IN_REG 4
-#define KSZ8795_COUNTER_NUM 0x20
+#define MIB_COUNTER_NUM 0x20
/* Common names used by other drivers */
@@ -856,12 +849,6 @@
#define P_MIRROR_CTRL REG_PORT_CTRL_1
#define P_802_1P_CTRL REG_PORT_CTRL_2
#define P_STP_CTRL REG_PORT_CTRL_2
-#define P_LOCAL_CTRL REG_PORT_CTRL_7
-#define P_REMOTE_STATUS REG_PORT_STATUS_0
-#define P_FORCE_CTRL REG_PORT_CTRL_9
-#define P_NEG_RESTART_CTRL REG_PORT_CTRL_10
-#define P_SPEED_STATUS REG_PORT_STATUS_1
-#define P_LINK_STATUS REG_PORT_STATUS_2
#define P_PASS_ALL_CTRL REG_PORT_CTRL_12
#define P_INS_SRC_PVID_CTRL REG_PORT_CTRL_12
#define P_DROP_TAG_CTRL REG_PORT_CTRL_13
@@ -876,7 +863,6 @@
#define S_MIRROR_CTRL REG_SW_CTRL_3
#define S_REPLACE_VID_CTRL REG_SW_CTRL_4
#define S_PASS_PAUSE_CTRL REG_SW_CTRL_10
-#define S_TAIL_TAG_CTRL REG_SW_CTRL_10
#define S_802_1P_PRIO_CTRL REG_SW_CTRL_12
#define S_TOS_PRIO_CTRL REG_TOS_PRIO_CTRL_0
#define S_IPV6_MLD_CTRL REG_SW_CTRL_21
@@ -890,65 +876,6 @@
#define BROADCAST_STORM_VALUE 9969
/**
- * STATIC_MAC_TABLE_ADDR 00-0000FFFF-FFFFFFFF
- * STATIC_MAC_TABLE_FWD_PORTS 00-001F0000-00000000
- * STATIC_MAC_TABLE_VALID 00-00200000-00000000
- * STATIC_MAC_TABLE_OVERRIDE 00-00400000-00000000
- * STATIC_MAC_TABLE_USE_FID 00-00800000-00000000
- * STATIC_MAC_TABLE_FID 00-7F000000-00000000
- */
-
-#define STATIC_MAC_TABLE_ADDR 0x0000FFFF
-#define STATIC_MAC_TABLE_FWD_PORTS 0x001F0000
-#define STATIC_MAC_TABLE_VALID 0x00200000
-#define STATIC_MAC_TABLE_OVERRIDE 0x00400000
-#define STATIC_MAC_TABLE_USE_FID 0x00800000
-#define STATIC_MAC_TABLE_FID 0x7F000000
-
-#define STATIC_MAC_FWD_PORTS_S 16
-#define STATIC_MAC_FID_S 24
-
-/**
- * VLAN_TABLE_FID 00-007F007F-007F007F
- * VLAN_TABLE_MEMBERSHIP 00-0F800F80-0F800F80
- * VLAN_TABLE_VALID 00-10001000-10001000
- */
-
-#define VLAN_TABLE_FID 0x007F
-#define VLAN_TABLE_MEMBERSHIP 0x0F80
-#define VLAN_TABLE_VALID 0x1000
-
-#define VLAN_TABLE_MEMBERSHIP_S 7
-#define VLAN_TABLE_S 16
-
-/**
- * DYNAMIC_MAC_TABLE_ADDR 00-0000FFFF-FFFFFFFF
- * DYNAMIC_MAC_TABLE_FID 00-007F0000-00000000
- * DYNAMIC_MAC_TABLE_NOT_READY 00-00800000-00000000
- * DYNAMIC_MAC_TABLE_SRC_PORT 00-07000000-00000000
- * DYNAMIC_MAC_TABLE_TIMESTAMP 00-18000000-00000000
- * DYNAMIC_MAC_TABLE_ENTRIES 7F-E0000000-00000000
- * DYNAMIC_MAC_TABLE_MAC_EMPTY 80-00000000-00000000
- */
-
-#define DYNAMIC_MAC_TABLE_ADDR 0x0000FFFF
-#define DYNAMIC_MAC_TABLE_FID 0x007F0000
-#define DYNAMIC_MAC_TABLE_SRC_PORT 0x07000000
-#define DYNAMIC_MAC_TABLE_TIMESTAMP 0x18000000
-#define DYNAMIC_MAC_TABLE_ENTRIES 0xE0000000
-
-#define DYNAMIC_MAC_TABLE_NOT_READY 0x80
-
-#define DYNAMIC_MAC_TABLE_ENTRIES_H 0x7F
-#define DYNAMIC_MAC_TABLE_MAC_EMPTY 0x80
-
-#define DYNAMIC_MAC_FID_S 16
-#define DYNAMIC_MAC_SRC_PORT_S 24
-#define DYNAMIC_MAC_TIMESTAMP_S 27
-#define DYNAMIC_MAC_ENTRIES_S 29
-#define DYNAMIC_MAC_ENTRIES_H_S 3
-
-/**
* MIB_COUNTER_VALUE 00-00000000-3FFFFFFF
* MIB_TOTAL_BYTES 00-0000000F-FFFFFFFF
* MIB_PACKET_DROPPED 00-00000000-0000FFFF
@@ -956,31 +883,15 @@
* MIB_COUNTER_OVERFLOW 00-00000040-00000000
*/
-#define MIB_COUNTER_OVERFLOW BIT(6)
-#define MIB_COUNTER_VALID BIT(5)
-
#define MIB_COUNTER_VALUE 0x3FFFFFFF
-#define KS_MIB_TOTAL_RX_0 0x100
-#define KS_MIB_TOTAL_TX_0 0x101
-#define KS_MIB_PACKET_DROPPED_RX_0 0x102
-#define KS_MIB_PACKET_DROPPED_TX_0 0x103
-#define KS_MIB_TOTAL_RX_1 0x104
-#define KS_MIB_TOTAL_TX_1 0x105
-#define KS_MIB_PACKET_DROPPED_TX_1 0x106
-#define KS_MIB_PACKET_DROPPED_RX_1 0x107
-#define KS_MIB_TOTAL_RX_2 0x108
-#define KS_MIB_TOTAL_TX_2 0x109
-#define KS_MIB_PACKET_DROPPED_TX_2 0x10A
-#define KS_MIB_PACKET_DROPPED_RX_2 0x10B
-#define KS_MIB_TOTAL_RX_3 0x10C
-#define KS_MIB_TOTAL_TX_3 0x10D
-#define KS_MIB_PACKET_DROPPED_TX_3 0x10E
-#define KS_MIB_PACKET_DROPPED_RX_3 0x10F
-#define KS_MIB_TOTAL_RX_4 0x110
-#define KS_MIB_TOTAL_TX_4 0x111
-#define KS_MIB_PACKET_DROPPED_TX_4 0x112
-#define KS_MIB_PACKET_DROPPED_RX_4 0x113
+#define KSZ8795_MIB_TOTAL_RX_0 0x100
+#define KSZ8795_MIB_TOTAL_TX_0 0x101
+#define KSZ8795_MIB_TOTAL_RX_1 0x104
+#define KSZ8795_MIB_TOTAL_TX_1 0x105
+
+#define KSZ8863_MIB_PACKET_DROPPED_TX_0 0x100
+#define KSZ8863_MIB_PACKET_DROPPED_RX_0 0x105
#define MIB_PACKET_DROPPED 0x0000FFFF
diff --git a/drivers/net/dsa/microchip/ksz8795_spi.c b/drivers/net/dsa/microchip/ksz8795_spi.c
index f98432a3e2b5..85ba12aa82d8 100644
--- a/drivers/net/dsa/microchip/ksz8795_spi.c
+++ b/drivers/net/dsa/microchip/ksz8795_spi.c
@@ -14,34 +14,52 @@
#include <linux/regmap.h>
#include <linux/spi/spi.h>
+#include "ksz8.h"
#include "ksz_common.h"
-#define SPI_ADDR_SHIFT 12
-#define SPI_ADDR_ALIGN 3
-#define SPI_TURNAROUND_SHIFT 1
+#define KSZ8795_SPI_ADDR_SHIFT 12
+#define KSZ8795_SPI_ADDR_ALIGN 3
+#define KSZ8795_SPI_TURNAROUND_SHIFT 1
-KSZ_REGMAP_TABLE(ksz8795, 16, SPI_ADDR_SHIFT,
- SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN);
+#define KSZ8863_SPI_ADDR_SHIFT 8
+#define KSZ8863_SPI_ADDR_ALIGN 8
+#define KSZ8863_SPI_TURNAROUND_SHIFT 0
+
+KSZ_REGMAP_TABLE(ksz8795, 16, KSZ8795_SPI_ADDR_SHIFT,
+ KSZ8795_SPI_TURNAROUND_SHIFT, KSZ8795_SPI_ADDR_ALIGN);
+
+KSZ_REGMAP_TABLE(ksz8863, 16, KSZ8863_SPI_ADDR_SHIFT,
+ KSZ8863_SPI_TURNAROUND_SHIFT, KSZ8863_SPI_ADDR_ALIGN);
static int ksz8795_spi_probe(struct spi_device *spi)
{
+ const struct regmap_config *regmap_config;
+ struct device *ddev = &spi->dev;
struct regmap_config rc;
struct ksz_device *dev;
- int i, ret;
+ struct ksz8 *ksz8;
+ int i, ret = 0;
- dev = ksz_switch_alloc(&spi->dev, spi);
+ ksz8 = devm_kzalloc(&spi->dev, sizeof(struct ksz8), GFP_KERNEL);
+ ksz8->priv = spi;
+
+ dev = ksz_switch_alloc(&spi->dev, ksz8);
if (!dev)
return -ENOMEM;
+ regmap_config = device_get_match_data(ddev);
+ if (!regmap_config)
+ return -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) {
- rc = ksz8795_regmap_config[i];
+ rc = regmap_config[i];
rc.lock_arg = &dev->regmap_mutex;
dev->regmap[i] = devm_regmap_init_spi(spi, &rc);
if (IS_ERR(dev->regmap[i])) {
ret = PTR_ERR(dev->regmap[i]);
dev_err(&spi->dev,
"Failed to initialize regmap%i: %d\n",
- ksz8795_regmap_config[i].val_bits, ret);
+ regmap_config[i].val_bits, ret);
return ret;
}
}
@@ -55,7 +73,7 @@ static int ksz8795_spi_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = ksz8795_switch_register(dev);
+ ret = ksz8_switch_register(dev);
/* Main DSA driver may not be started yet. */
if (ret)
@@ -85,9 +103,11 @@ static void ksz8795_spi_shutdown(struct spi_device *spi)
}
static const struct of_device_id ksz8795_dt_ids[] = {
- { .compatible = "microchip,ksz8765" },
- { .compatible = "microchip,ksz8794" },
- { .compatible = "microchip,ksz8795" },
+ { .compatible = "microchip,ksz8765", .data = &ksz8795_regmap_config },
+ { .compatible = "microchip,ksz8794", .data = &ksz8795_regmap_config },
+ { .compatible = "microchip,ksz8795", .data = &ksz8795_regmap_config },
+ { .compatible = "microchip,ksz8863", .data = &ksz8863_regmap_config },
+ { .compatible = "microchip,ksz8873", .data = &ksz8863_regmap_config },
{},
};
MODULE_DEVICE_TABLE(of, ksz8795_dt_ids);
diff --git a/drivers/net/dsa/microchip/ksz8863_smi.c b/drivers/net/dsa/microchip/ksz8863_smi.c
new file mode 100644
index 000000000000..30d97ea7a949
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz8863_smi.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip KSZ8863 series register access through SMI
+ *
+ * Copyright (C) 2019 Pengutronix, Michael Grzeschik <[email protected]>
+ */
+
+#include "ksz8.h"
+#include "ksz_common.h"
+
+/* Serial Management Interface (SMI) uses the following frame format:
+ *
+ * preamble|start|Read/Write| PHY | REG |TA| Data bits | Idle
+ * |frame| OP code |address |address| | |
+ * read | 32x1´s | 01 | 00 | 1xRRR | RRRRR |Z0| 00000000DDDDDDDD | Z
+ * write| 32x1´s | 01 | 00 | 0xRRR | RRRRR |10| xxxxxxxxDDDDDDDD | Z
+ *
+ */
+
+#define SMI_KSZ88XX_READ_PHY BIT(4)
+
+static int ksz8863_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,
+ void *val_buf, size_t val_len)
+{
+ struct ksz_device *dev = ctx;
+ struct mdio_device *mdev;
+ u8 reg = *(u8 *)reg_buf;
+ u8 *val = val_buf;
+ struct ksz8 *ksz8;
+ int i, ret = 0;
+
+ ksz8 = dev->priv;
+ mdev = ksz8->priv;
+
+ mutex_lock_nested(&mdev->bus->mdio_lock, MDIO_MUTEX_NESTED);
+ for (i = 0; i < val_len; i++) {
+ int tmp = reg + i;
+
+ ret = __mdiobus_read(mdev->bus, ((tmp & 0xE0) >> 5) |
+ SMI_KSZ88XX_READ_PHY, tmp);
+ if (ret < 0)
+ goto out;
+
+ val[i] = ret;
+ }
+ ret = 0;
+
+ out:
+ mutex_unlock(&mdev->bus->mdio_lock);
+
+ return ret;
+}
+
+static int ksz8863_mdio_write(void *ctx, const void *data, size_t count)
+{
+ struct ksz_device *dev = ctx;
+ struct mdio_device *mdev;
+ struct ksz8 *ksz8;
+ int i, ret = 0;
+ u32 reg;
+ u8 *val;
+
+ ksz8 = dev->priv;
+ mdev = ksz8->priv;
+
+ val = (u8 *)(data + 4);
+ reg = *(u32 *)data;
+
+ mutex_lock_nested(&mdev->bus->mdio_lock, MDIO_MUTEX_NESTED);
+ for (i = 0; i < (count - 4); i++) {
+ int tmp = reg + i;
+
+ ret = __mdiobus_write(mdev->bus, ((tmp & 0xE0) >> 5),
+ tmp, val[i]);
+ if (ret < 0)
+ goto out;
+ }
+
+ out:
+ mutex_unlock(&mdev->bus->mdio_lock);
+
+ return ret;
+}
+
+static const struct regmap_bus regmap_smi[] = {
+ {
+ .read = ksz8863_mdio_read,
+ .write = ksz8863_mdio_write,
+ .max_raw_read = 1,
+ .max_raw_write = 1,
+ },
+ {
+ .read = ksz8863_mdio_read,
+ .write = ksz8863_mdio_write,
+ .val_format_endian_default = REGMAP_ENDIAN_BIG,
+ .max_raw_read = 2,
+ .max_raw_write = 2,
+ },
+ {
+ .read = ksz8863_mdio_read,
+ .write = ksz8863_mdio_write,
+ .val_format_endian_default = REGMAP_ENDIAN_BIG,
+ .max_raw_read = 4,
+ .max_raw_write = 4,
+ }
+};
+
+static const struct regmap_config ksz8863_regmap_config[] = {
+ {
+ .name = "#8",
+ .reg_bits = 8,
+ .pad_bits = 24,
+ .val_bits = 8,
+ .cache_type = REGCACHE_NONE,
+ .use_single_read = 1,
+ .lock = ksz_regmap_lock,
+ .unlock = ksz_regmap_unlock,
+ },
+ {
+ .name = "#16",
+ .reg_bits = 8,
+ .pad_bits = 24,
+ .val_bits = 16,
+ .cache_type = REGCACHE_NONE,
+ .use_single_read = 1,
+ .lock = ksz_regmap_lock,
+ .unlock = ksz_regmap_unlock,
+ },
+ {
+ .name = "#32",
+ .reg_bits = 8,
+ .pad_bits = 24,
+ .val_bits = 32,
+ .cache_type = REGCACHE_NONE,
+ .use_single_read = 1,
+ .lock = ksz_regmap_lock,
+ .unlock = ksz_regmap_unlock,
+ }
+};
+
+static int ksz8863_smi_probe(struct mdio_device *mdiodev)
+{
+ struct regmap_config rc;
+ struct ksz_device *dev;
+ struct ksz8 *ksz8;
+ int ret;
+ int i;
+
+ ksz8 = devm_kzalloc(&mdiodev->dev, sizeof(struct ksz8), GFP_KERNEL);
+ ksz8->priv = mdiodev;
+
+ dev = ksz_switch_alloc(&mdiodev->dev, ksz8);
+ if (!dev)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(ksz8863_regmap_config); i++) {
+ rc = ksz8863_regmap_config[i];
+ rc.lock_arg = &dev->regmap_mutex;
+ dev->regmap[i] = devm_regmap_init(&mdiodev->dev,
+ &regmap_smi[i], dev,
+ &rc);
+ if (IS_ERR(dev->regmap[i])) {
+ ret = PTR_ERR(dev->regmap[i]);
+ dev_err(&mdiodev->dev,
+ "Failed to initialize regmap%i: %d\n",
+ ksz8863_regmap_config[i].val_bits, ret);
+ return ret;
+ }
+ }
+
+ if (mdiodev->dev.platform_data)
+ dev->pdata = mdiodev->dev.platform_data;
+
+ ret = ksz8_switch_register(dev);
+
+ /* Main DSA driver may not be started yet. */
+ if (ret)
+ return ret;
+
+ dev_set_drvdata(&mdiodev->dev, dev);
+
+ return 0;
+}
+
+static void ksz8863_smi_remove(struct mdio_device *mdiodev)
+{
+ struct ksz_device *dev = dev_get_drvdata(&mdiodev->dev);
+
+ if (dev)
+ ksz_switch_remove(dev);
+}
+
+static const struct of_device_id ksz8863_dt_ids[] = {
+ { .compatible = "microchip,ksz8863" },
+ { .compatible = "microchip,ksz8873" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ksz8863_dt_ids);
+
+static struct mdio_driver ksz8863_driver = {
+ .probe = ksz8863_smi_probe,
+ .remove = ksz8863_smi_remove,
+ .mdiodrv.driver = {
+ .name = "ksz8863-switch",
+ .of_match_table = ksz8863_dt_ids,
+ },
+};
+
+mdio_module_driver(ksz8863_driver);
+
+MODULE_AUTHOR("Michael Grzeschik <[email protected]>");
+MODULE_DESCRIPTION("Microchip KSZ8863 SMI Switch driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index f212775372ce..e0bbdca64375 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -71,6 +71,7 @@ struct ksz_device {
int port_cnt;
int reg_mib_cnt;
int mib_cnt;
+ const struct mib_names *mib_names;
phy_interface_t compat_interface;
u32 regs_size;
bool phy_errata_9477;
@@ -142,7 +143,7 @@ int ksz_switch_register(struct ksz_device *dev,
const struct ksz_dev_ops *ops);
void ksz_switch_remove(struct ksz_device *dev);
-int ksz8795_switch_register(struct ksz_device *dev);
+int ksz8_switch_register(struct ksz_device *dev);
int ksz9477_switch_register(struct ksz_device *dev);
void ksz_update_port_member(struct ksz_device *dev, int port);
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index 094d17a1d037..8f74ffc7a279 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -468,30 +468,38 @@ long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp)
return restart ? 1 : -1;
}
-bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
- struct sk_buff *clone, unsigned int type)
+void mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb)
{
struct mv88e6xxx_chip *chip = ds->priv;
struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
struct ptp_header *hdr;
+ struct sk_buff *clone;
+ unsigned int type;
- if (!(skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP))
- return false;
+ type = ptp_classify_raw(skb);
+ if (type == PTP_CLASS_NONE)
+ return;
- hdr = mv88e6xxx_should_tstamp(chip, port, clone, type);
+ hdr = mv88e6xxx_should_tstamp(chip, port, skb, type);
if (!hdr)
- return false;
+ return;
+
+ clone = skb_clone_sk(skb);
+ if (!clone)
+ return;
if (test_and_set_bit_lock(MV88E6XXX_HWTSTAMP_TX_IN_PROGRESS,
- &ps->state))
- return false;
+ &ps->state)) {
+ kfree_skb(clone);
+ return;
+ }
ps->tx_skb = clone;
ps->tx_tstamp_start = jiffies;
ps->tx_seq_id = be16_to_cpu(hdr->sequence_id);
ptp_schedule_worker(chip->ptp_clock, 0);
- return true;
}
int mv88e6165_global_disable(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.h b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
index 9da9f197ba02..cf7fb6d660b1 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.h
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
@@ -117,8 +117,8 @@ int mv88e6xxx_port_hwtstamp_get(struct dsa_switch *ds, int port,
bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *clone, unsigned int type);
-bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
- struct sk_buff *clone, unsigned int type);
+void mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb);
int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
struct ethtool_ts_info *info);
@@ -151,11 +151,9 @@ static inline bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
return false;
}
-static inline bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
- struct sk_buff *clone,
- unsigned int type)
+static inline void mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb)
{
- return false;
}
static inline int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 470856bcd2f3..e4fbef81bc52 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -443,15 +443,15 @@ int mv88e6185_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
int mv88e6185_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{
/* There are no configurable serdes lanes on this switch chip but we
- * need to return non-zero so that callers of
+ * need to return a non-negative lane number so that callers of
* mv88e6xxx_serdes_get_lane() know this is a serdes port.
*/
switch (chip->ports[port].cmode) {
case MV88E6185_PORT_STS_CMODE_SERDES:
case MV88E6185_PORT_STS_CMODE_1000BASE_X:
- return 0xff;
- default:
return 0;
+ default:
+ return -ENODEV;
}
}
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 6b5442be0230..ce607fbaaa3a 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -1395,19 +1395,20 @@ static bool felix_rxtstamp(struct dsa_switch *ds, int port,
return false;
}
-static bool felix_txtstamp(struct dsa_switch *ds, int port,
- struct sk_buff *clone, unsigned int type)
+static void felix_txtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb)
{
struct ocelot *ocelot = ds->priv;
- struct ocelot_port *ocelot_port = ocelot->ports[port];
+ struct sk_buff *clone = NULL;
- if (ocelot->ptp && (skb_shinfo(clone)->tx_flags & SKBTX_HW_TSTAMP) &&
- ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
- ocelot_port_add_txtstamp_skb(ocelot, port, clone);
- return true;
- }
+ if (!ocelot->ptp)
+ return;
- return false;
+ if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone))
+ return;
+
+ if (clone)
+ OCELOT_SKB_CB(skb)->clone = clone;
}
static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index d9c198ca0197..405024b637d6 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -3137,7 +3137,7 @@ static void sja1105_port_deferred_xmit(struct kthread_work *work)
struct sk_buff *skb;
while ((skb = skb_dequeue(&sp->xmit_queue)) != NULL) {
- struct sk_buff *clone = DSA_SKB_CB(skb)->clone;
+ struct sk_buff *clone = SJA1105_SKB_CB(skb)->clone;
mutex_lock(&priv->mgmt_lock);
diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c
index 1b90570b257b..0bc566b9e958 100644
--- a/drivers/net/dsa/sja1105/sja1105_ptp.c
+++ b/drivers/net/dsa/sja1105/sja1105_ptp.c
@@ -431,20 +431,24 @@ bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
return true;
}
-/* Called from dsa_skb_tx_timestamp. This callback is just to make DSA clone
- * the skb and have it available in DSA_SKB_CB in the .port_deferred_xmit
+/* Called from dsa_skb_tx_timestamp. This callback is just to clone
+ * the skb and have it available in SJA1105_SKB_CB in the .port_deferred_xmit
* callback, where we will timestamp it synchronously.
*/
-bool sja1105_port_txtstamp(struct dsa_switch *ds, int port,
- struct sk_buff *skb, unsigned int type)
+void sja1105_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
{
struct sja1105_private *priv = ds->priv;
struct sja1105_port *sp = &priv->ports[port];
+ struct sk_buff *clone;
if (!sp->hwts_tx_en)
- return false;
+ return;
- return true;
+ clone = skb_clone_sk(skb);
+ if (!clone)
+ return;
+
+ SJA1105_SKB_CB(skb)->clone = clone;
}
static int sja1105_ptp_reset(struct dsa_switch *ds)
diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h
index 3daa33e98e77..34f97f58a355 100644
--- a/drivers/net/dsa/sja1105/sja1105_ptp.h
+++ b/drivers/net/dsa/sja1105/sja1105_ptp.h
@@ -104,8 +104,8 @@ void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot,
bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb, unsigned int type);
-bool sja1105_port_txtstamp(struct dsa_switch *ds, int port,
- struct sk_buff *skb, unsigned int type);
+void sja1105_port_txtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb);
int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr);
diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c
index f78daba60b35..aa412506832d 100644
--- a/drivers/net/ethernet/amd/pcnet32.c
+++ b/drivers/net/ethernet/amd/pcnet32.c
@@ -2853,8 +2853,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
netif_info(lp, link, dev, "link down\n");
}
if (lp->phycount > 1) {
- curr_link = pcnet32_check_otherphy(dev);
- prev_link = 0;
+ pcnet32_check_otherphy(dev);
}
} else if (verbose || !prev_link) {
netif_carrier_on(dev);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 5d0ab5629aa4..39ac9e2f5118 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -1755,14 +1755,16 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
cons = rxcmp->rx_cmp_opaque;
if (unlikely(cons != rxr->rx_next_cons)) {
- int rc1 = bnxt_discard_rx(bp, cpr, raw_cons, rxcmp);
+ int rc1 = bnxt_discard_rx(bp, cpr, &tmp_raw_cons, rxcmp);
/* 0xffff is forced error, don't print it */
if (rxr->rx_next_cons != 0xffff)
netdev_warn(bp->dev, "RX cons %x != expected cons %x\n",
cons, rxr->rx_next_cons);
bnxt_sched_reset(bp, rxr);
- return rc1;
+ if (rc1)
+ return rc1;
+ goto next_rx_no_prod_no_len;
}
rx_buf = &rxr->rx_buf_ring[cons];
data = rx_buf->data;
@@ -9804,7 +9806,9 @@ static ssize_t bnxt_show_temp(struct device *dev,
if (!rc)
len = sprintf(buf, "%u\n", resp->temp * 1000); /* display millidegree */
mutex_unlock(&bp->hwrm_cmd_lock);
- return rc ?: len;
+ if (rc)
+ return rc;
+ return len;
}
static SENSOR_DEVICE_ATTR(temp1_input, 0444, bnxt_show_temp, NULL, 0);
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index e7f7121821be..2a8bf53c2f75 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -1522,7 +1522,6 @@ dm9000_probe(struct platform_device *pdev)
if (ret) {
dev_err(db->dev, "irq %d cannot set wakeup (%d)\n",
db->irq_wake, ret);
- ret = 0;
} else {
irq_set_irq_wake(db->irq_wake, 0);
db->wake_supported = 1;
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_main.c b/drivers/net/ethernet/marvell/prestera/prestera_main.c
index f08c420a5803..2768c78528a5 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_main.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_main.c
@@ -431,7 +431,8 @@ static void prestera_port_handle_event(struct prestera_switch *sw,
netif_carrier_on(port->dev);
if (!delayed_work_pending(caching_dw))
queue_delayed_work(prestera_wq, caching_dw, 0);
- } else {
+ } else if (netif_running(port->dev) &&
+ netif_carrier_ok(port->dev)) {
netif_carrier_off(port->dev);
if (delayed_work_pending(caching_dw))
cancel_delayed_work(caching_dw);
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 8d06ffaf318a..0c4283319d7f 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -6,6 +6,7 @@
*/
#include <linux/dsa/ocelot.h>
#include <linux/if_bridge.h>
+#include <linux/ptp_classify.h>
#include <soc/mscc/ocelot_vcap.h>
#include "ocelot.h"
#include "ocelot_vcap.h"
@@ -530,22 +531,92 @@ void ocelot_port_disable(struct ocelot *ocelot, int port)
}
EXPORT_SYMBOL(ocelot_port_disable);
-void ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port,
- struct sk_buff *clone)
+static void ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port,
+ struct sk_buff *clone)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
spin_lock(&ocelot_port->ts_id_lock);
skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
- /* Store timestamp ID in cb[0] of sk_buff */
- clone->cb[0] = ocelot_port->ts_id;
+ /* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */
+ OCELOT_SKB_CB(clone)->ts_id = ocelot_port->ts_id;
ocelot_port->ts_id = (ocelot_port->ts_id + 1) % 4;
skb_queue_tail(&ocelot_port->tx_skbs, clone);
spin_unlock(&ocelot_port->ts_id_lock);
}
-EXPORT_SYMBOL(ocelot_port_add_txtstamp_skb);
+
+u32 ocelot_ptp_rew_op(struct sk_buff *skb)
+{
+ struct sk_buff *clone = OCELOT_SKB_CB(skb)->clone;
+ u8 ptp_cmd = OCELOT_SKB_CB(skb)->ptp_cmd;
+ u32 rew_op = 0;
+
+ if (ptp_cmd == IFH_REW_OP_TWO_STEP_PTP && clone) {
+ rew_op = ptp_cmd;
+ rew_op |= OCELOT_SKB_CB(clone)->ts_id << 3;
+ } else if (ptp_cmd == IFH_REW_OP_ORIGIN_PTP) {
+ rew_op = ptp_cmd;
+ }
+
+ return rew_op;
+}
+EXPORT_SYMBOL(ocelot_ptp_rew_op);
+
+static bool ocelot_ptp_is_onestep_sync(struct sk_buff *skb)
+{
+ struct ptp_header *hdr;
+ unsigned int ptp_class;
+ u8 msgtype, twostep;
+
+ ptp_class = ptp_classify_raw(skb);
+ if (ptp_class == PTP_CLASS_NONE)
+ return false;
+
+ hdr = ptp_parse_header(skb, ptp_class);
+ if (!hdr)
+ return false;
+
+ msgtype = ptp_get_msgtype(hdr, ptp_class);
+ twostep = hdr->flag_field[0] & 0x2;
+
+ if (msgtype == PTP_MSGTYPE_SYNC && twostep == 0)
+ return true;
+
+ return false;
+}
+
+int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port,
+ struct sk_buff *skb,
+ struct sk_buff **clone)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ u8 ptp_cmd = ocelot_port->ptp_cmd;
+
+ /* Store ptp_cmd in OCELOT_SKB_CB(skb)->ptp_cmd */
+ if (ptp_cmd == IFH_REW_OP_ORIGIN_PTP) {
+ if (ocelot_ptp_is_onestep_sync(skb)) {
+ OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd;
+ return 0;
+ }
+
+ /* Fall back to two-step timestamping */
+ ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
+ }
+
+ if (ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
+ *clone = skb_clone_sk(skb);
+ if (!(*clone))
+ return -ENOMEM;
+
+ ocelot_port_add_txtstamp_skb(ocelot, port, *clone);
+ OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ocelot_port_txtstamp_request);
static void ocelot_get_hwtimestamp(struct ocelot *ocelot,
struct timespec64 *ts)
@@ -604,7 +675,7 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
spin_lock_irqsave(&port->tx_skbs.lock, flags);
skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) {
- if (skb->cb[0] != id)
+ if (OCELOT_SKB_CB(skb)->ts_id != id)
continue;
__skb_unlink(skb, &port->tx_skbs);
skb_match = skb;
diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c
index 36f32a4d9b0f..aad33d22c33f 100644
--- a/drivers/net/ethernet/mscc/ocelot_net.c
+++ b/drivers/net/ethernet/mscc/ocelot_net.c
@@ -507,21 +507,17 @@ static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
/* Check if timestamping is needed */
if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
- rew_op = ocelot_port->ptp_cmd;
+ struct sk_buff *clone = NULL;
- if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
- struct sk_buff *clone;
-
- clone = skb_clone_sk(skb);
- if (!clone) {
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
+ if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone)) {
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
- ocelot_port_add_txtstamp_skb(ocelot, port, clone);
+ if (clone)
+ OCELOT_SKB_CB(skb)->clone = clone;
- rew_op |= clone->cb[0] << 3;
- }
+ rew_op = ocelot_ptp_rew_op(skb);
}
ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
index 713ee3041d49..bea978df7713 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
@@ -364,6 +364,7 @@ int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
attrs.split = eth_port.is_split;
attrs.splittable = !attrs.split;
+ attrs.lanes = eth_port.port_lanes;
attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
attrs.phys.port_number = eth_port.label_port;
attrs.phys.split_subport_number = eth_port.label_subport;
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-mac.c b/drivers/net/ethernet/qualcomm/emac/emac-mac.c
index 117188e3c7de..87b8c032195d 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-mac.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac-mac.c
@@ -1437,6 +1437,7 @@ netdev_tx_t emac_mac_tx_buf_send(struct emac_adapter *adpt,
{
struct emac_tpd tpd;
u32 prod_idx;
+ int len;
memset(&tpd, 0, sizeof(tpd));
@@ -1456,9 +1457,10 @@ netdev_tx_t emac_mac_tx_buf_send(struct emac_adapter *adpt,
if (skb_network_offset(skb) != ETH_HLEN)
TPD_TYP_SET(&tpd, 1);
+ len = skb->len;
emac_tx_fill_tpd(adpt, tx_q, skb, &tpd);
- netdev_sent_queue(adpt->netdev, skb->len);
+ netdev_sent_queue(adpt->netdev, len);
/* Make sure the are enough free descriptors to hold one
* maximum-sized SKB. We need one desc for each fragment,
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 9e5dad41cdc9..4afff320dfd0 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -913,31 +913,20 @@ static int ravb_poll(struct napi_struct *napi, int budget)
int q = napi - priv->napi;
int mask = BIT(q);
int quota = budget;
- u32 ris0, tis;
- for (;;) {
- tis = ravb_read(ndev, TIS);
- ris0 = ravb_read(ndev, RIS0);
- if (!((ris0 & mask) || (tis & mask)))
- break;
+ /* Processing RX Descriptor Ring */
+ /* Clear RX interrupt */
+ ravb_write(ndev, ~(mask | RIS0_RESERVED), RIS0);
+ if (ravb_rx(ndev, &quota, q))
+ goto out;
- /* Processing RX Descriptor Ring */
- if (ris0 & mask) {
- /* Clear RX interrupt */
- ravb_write(ndev, ~(mask | RIS0_RESERVED), RIS0);
- if (ravb_rx(ndev, &quota, q))
- goto out;
- }
- /* Processing TX Descriptor Ring */
- if (tis & mask) {
- spin_lock_irqsave(&priv->lock, flags);
- /* Clear TX interrupt */
- ravb_write(ndev, ~(mask | TIS_RESERVED), TIS);
- ravb_tx_free(ndev, q, true);
- netif_wake_subqueue(ndev, q);
- spin_unlock_irqrestore(&priv->lock, flags);
- }
- }
+ /* Processing RX Descriptor Ring */
+ spin_lock_irqsave(&priv->lock, flags);
+ /* Clear TX interrupt */
+ ravb_write(ndev, ~(mask | TIS_RESERVED), TIS);
+ ravb_tx_free(ndev, q, true);
+ netif_wake_subqueue(ndev, q);
+ spin_unlock_irqrestore(&priv->lock, flags);
napi_complete(napi);
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index c873f961d5a5..c3f35da1b82a 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -2944,8 +2944,7 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
/* Get the transmit queue */
tx_ev_q_label = EFX_QWORD_FIELD(*event, ESF_DZ_TX_QLABEL);
- tx_queue = efx_channel_get_tx_queue(channel,
- tx_ev_q_label % EFX_MAX_TXQ_PER_CHANNEL);
+ tx_queue = channel->tx_queue + (tx_ev_q_label % EFX_MAX_TXQ_PER_CHANNEL);
if (!tx_queue->timestamping) {
/* Transmit completion */
diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c
index 1bfeee283ea9..a3ca406a3561 100644
--- a/drivers/net/ethernet/sfc/efx_channels.c
+++ b/drivers/net/ethernet/sfc/efx_channels.c
@@ -914,6 +914,8 @@ int efx_set_channels(struct efx_nic *efx)
}
}
}
+ if (xdp_queue_number)
+ efx->xdp_tx_queue_count = xdp_queue_number;
rc = netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
if (rc)
diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c
index d75cf5ff5686..49df02ecee91 100644
--- a/drivers/net/ethernet/sfc/farch.c
+++ b/drivers/net/ethernet/sfc/farch.c
@@ -835,14 +835,14 @@ efx_farch_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
/* Transmit completion */
tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR);
tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL);
- tx_queue = efx_channel_get_tx_queue(
- channel, tx_ev_q_label % EFX_MAX_TXQ_PER_CHANNEL);
+ tx_queue = channel->tx_queue +
+ (tx_ev_q_label % EFX_MAX_TXQ_PER_CHANNEL);
efx_xmit_done(tx_queue, tx_ev_desc_ptr);
} else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) {
/* Rewrite the FIFO write pointer */
tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL);
- tx_queue = efx_channel_get_tx_queue(
- channel, tx_ev_q_label % EFX_MAX_TXQ_PER_CHANNEL);
+ tx_queue = channel->tx_queue +
+ (tx_ev_q_label % EFX_MAX_TXQ_PER_CHANNEL);
netif_tx_lock(efx->net_dev);
efx_farch_notify_tx_desc(tx_queue);
@@ -1081,16 +1081,16 @@ static void
efx_farch_handle_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)
{
struct efx_tx_queue *tx_queue;
+ struct efx_channel *channel;
int qid;
qid = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA);
if (qid < EFX_MAX_TXQ_PER_CHANNEL * (efx->n_tx_channels + efx->n_extra_tx_channels)) {
- tx_queue = efx_get_tx_queue(efx, qid / EFX_MAX_TXQ_PER_CHANNEL,
- qid % EFX_MAX_TXQ_PER_CHANNEL);
- if (atomic_cmpxchg(&tx_queue->flush_outstanding, 1, 0)) {
+ channel = efx_get_tx_channel(efx, qid / EFX_MAX_TXQ_PER_CHANNEL);
+ tx_queue = channel->tx_queue + (qid % EFX_MAX_TXQ_PER_CHANNEL);
+ if (atomic_cmpxchg(&tx_queue->flush_outstanding, 1, 0))
efx_farch_magic_event(tx_queue->channel,
EFX_CHANNEL_MAGIC_TX_DRAIN(tx_queue));
- }
}
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 372090e8ee6f..a9a984c57d78 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3303,8 +3303,15 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
/* Enable TSO */
if (priv->tso) {
- for (chan = 0; chan < tx_cnt; chan++)
+ for (chan = 0; chan < tx_cnt; chan++) {
+ struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan];
+
+ /* TSO and TBS cannot co-exist */
+ if (tx_q->tbs & STMMAC_TBS_AVAIL)
+ continue;
+
stmmac_enable_tso(priv, priv->ioaddr, 1, chan);
+ }
}
/* Enable Split Header */
@@ -3674,9 +3681,8 @@ int stmmac_open(struct net_device *dev)
struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan];
int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en;
+ /* Setup per-TXQ tbs flag before TX descriptor alloc */
tx_q->tbs |= tbs_en ? STMMAC_TBS_AVAIL : 0;
- if (stmmac_enable_tbs(priv, priv->ioaddr, tbs_en, chan))
- tx_q->tbs &= ~STMMAC_TBS_AVAIL;
}
ret = alloc_dma_desc_resources(priv);
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index 14e7da7d302f..f9417b44cae8 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -169,11 +169,11 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
/* EMAC mac_status register */
#define EMAC_MACSTATUS_TXERRCODE_MASK (0xF00000)
#define EMAC_MACSTATUS_TXERRCODE_SHIFT (20)
-#define EMAC_MACSTATUS_TXERRCH_MASK (0x7)
+#define EMAC_MACSTATUS_TXERRCH_MASK (0x70000)
#define EMAC_MACSTATUS_TXERRCH_SHIFT (16)
#define EMAC_MACSTATUS_RXERRCODE_MASK (0xF000)
#define EMAC_MACSTATUS_RXERRCODE_SHIFT (12)
-#define EMAC_MACSTATUS_RXERRCH_MASK (0x7)
+#define EMAC_MACSTATUS_RXERRCH_MASK (0x700)
#define EMAC_MACSTATUS_RXERRCH_SHIFT (8)
/* EMAC RX register masks */
diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
index 1149e88e6454..cb89323855d8 100644
--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -1087,7 +1087,7 @@ static int init_queues(struct port *port)
int i;
if (!ports_open) {
- dma_pool = dma_pool_create(DRV_NAME, port->netdev->dev.parent,
+ dma_pool = dma_pool_create(DRV_NAME, &port->netdev->dev,
POOL_ALLOC_SIZE, 32, 0);
if (!dma_pool)
return -ENOMEM;
@@ -1506,6 +1506,9 @@ static int ixp4xx_eth_probe(struct platform_device *pdev)
ndev->netdev_ops = &ixp4xx_netdev_ops;
ndev->ethtool_ops = &ixp4xx_ethtool_ops;
ndev->tx_queue_len = 100;
+ /* Inherit the DMA masks from the platform device */
+ ndev->dev.dma_mask = dev->dma_mask;
+ ndev->dev.coherent_dma_mask = dev->coherent_dma_mask;
netif_napi_add(ndev, &port->napi, eth_poll, NAPI_WEIGHT);
diff --git a/drivers/net/fddi/skfp/h/smc.h b/drivers/net/fddi/skfp/h/smc.h
index 706fa619b703..3814a2ff64ae 100644
--- a/drivers/net/fddi/skfp/h/smc.h
+++ b/drivers/net/fddi/skfp/h/smc.h
@@ -228,7 +228,7 @@ struct s_phy {
u_char timer1_exp ;
u_char timer2_exp ;
u_char pcm_pad1[1] ;
- int cem_pst ; /* CEM privae state; used for dual homing */
+ int cem_pst ; /* CEM private state; used for dual homing */
struct lem_counter lem ;
#ifdef AMDPLC
struct s_plc plc ;
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 072de880b99f..1ab94b5f9bbf 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -892,7 +892,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
__be16 sport;
int err;
- if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
+ if (!pskb_inet_may_pull(skb))
return -EINVAL;
sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
@@ -989,7 +989,7 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
__be16 sport;
int err;
- if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
+ if (!pskb_inet_may_pull(skb))
return -EINVAL;
sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 7427b989607e..1b998aa481f8 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -272,25 +272,22 @@ static void macvlan_broadcast(struct sk_buff *skb,
if (skb->protocol == htons(ETH_P_PAUSE))
return;
- for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
- hlist_for_each_entry_rcu(vlan, &port->vlan_hash[i], hlist) {
- if (vlan->dev == src || !(vlan->mode & mode))
- continue;
+ hash_for_each_rcu(port->vlan_hash, i, vlan, hlist) {
+ if (vlan->dev == src || !(vlan->mode & mode))
+ continue;
- hash = mc_hash(vlan, eth->h_dest);
- if (!test_bit(hash, vlan->mc_filter))
- continue;
+ hash = mc_hash(vlan, eth->h_dest);
+ if (!test_bit(hash, vlan->mc_filter))
+ continue;
- err = NET_RX_DROP;
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (likely(nskb))
- err = macvlan_broadcast_one(
- nskb, vlan, eth,
+ err = NET_RX_DROP;
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (likely(nskb))
+ err = macvlan_broadcast_one(nskb, vlan, eth,
mode == MACVLAN_MODE_BRIDGE) ?:
- netif_rx_ni(nskb);
- macvlan_count_rx(vlan, skb->len + ETH_HLEN,
- err == NET_RX_SUCCESS, true);
- }
+ netif_rx_ni(nskb);
+ macvlan_count_rx(vlan, skb->len + ETH_HLEN,
+ err == NET_RX_SUCCESS, true);
}
}
@@ -380,20 +377,14 @@ err:
static void macvlan_flush_sources(struct macvlan_port *port,
struct macvlan_dev *vlan)
{
+ struct macvlan_source_entry *entry;
+ struct hlist_node *next;
int i;
- for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
- struct hlist_node *h, *n;
-
- hlist_for_each_safe(h, n, &port->vlan_source_hash[i]) {
- struct macvlan_source_entry *entry;
+ hash_for_each_safe(port->vlan_source_hash, i, next, entry, hlist)
+ if (entry->vlan == vlan)
+ macvlan_hash_del_source(entry);
- entry = hlist_entry(h, struct macvlan_source_entry,
- hlist);
- if (entry->vlan == vlan)
- macvlan_hash_del_source(entry);
- }
- }
vlan->macaddr_count = 0;
}
diff --git a/drivers/net/mdio/mdio-bitbang.c b/drivers/net/mdio/mdio-bitbang.c
index 0f457c436335..07609114a26b 100644
--- a/drivers/net/mdio/mdio-bitbang.c
+++ b/drivers/net/mdio/mdio-bitbang.c
@@ -158,7 +158,7 @@ int mdiobb_read(struct mii_bus *bus, int phy, int reg)
reg = mdiobb_cmd_addr(ctrl, phy, reg);
mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
} else
- mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
+ mdiobb_cmd(ctrl, ctrl->op_c22_read, phy, reg);
ctrl->ops->set_mdio_dir(ctrl, 0);
@@ -190,7 +190,7 @@ int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
reg = mdiobb_cmd_addr(ctrl, phy, reg);
mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
} else
- mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
+ mdiobb_cmd(ctrl, ctrl->op_c22_write, phy, reg);
/* send the turnaround (10) */
mdiobb_send_bit(ctrl, 1);
@@ -217,6 +217,10 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
bus->read = mdiobb_read;
bus->write = mdiobb_write;
bus->priv = ctrl;
+ if (!ctrl->override_op_c22) {
+ ctrl->op_c22_read = MDIO_READ;
+ ctrl->op_c22_write = MDIO_WRITE;
+ }
return bus;
}
diff --git a/drivers/net/mdio/mdio-gpio.c b/drivers/net/mdio/mdio-gpio.c
index 56c8f914f893..0fb3c2de0845 100644
--- a/drivers/net/mdio/mdio-gpio.c
+++ b/drivers/net/mdio/mdio-gpio.c
@@ -132,6 +132,13 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask;
}
+ if (dev->of_node &&
+ of_device_is_compatible(dev->of_node, "microchip,mdio-smi0")) {
+ bitbang->ctrl.op_c22_read = 0;
+ bitbang->ctrl.op_c22_write = 0;
+ bitbang->ctrl.override_op_c22 = 1;
+ }
+
dev_set_drvdata(dev, new_bus);
return new_bus;
@@ -196,6 +203,7 @@ static int mdio_gpio_remove(struct platform_device *pdev)
static const struct of_device_id mdio_gpio_of_match[] = {
{ .compatible = "virtual,mdio-gpio", },
+ { .compatible = "microchip,mdio-smi0" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mdio_gpio_of_match);
diff --git a/drivers/net/phy/intel-xway.c b/drivers/net/phy/intel-xway.c
index 6eac50d4b42f..d453ec016168 100644
--- a/drivers/net/phy/intel-xway.c
+++ b/drivers/net/phy/intel-xway.c
@@ -11,6 +11,18 @@
#define XWAY_MDIO_IMASK 0x19 /* interrupt mask */
#define XWAY_MDIO_ISTAT 0x1A /* interrupt status */
+#define XWAY_MDIO_LED 0x1B /* led control */
+
+/* bit 15:12 are reserved */
+#define XWAY_MDIO_LED_LED3_EN BIT(11) /* Enable the integrated function of LED3 */
+#define XWAY_MDIO_LED_LED2_EN BIT(10) /* Enable the integrated function of LED2 */
+#define XWAY_MDIO_LED_LED1_EN BIT(9) /* Enable the integrated function of LED1 */
+#define XWAY_MDIO_LED_LED0_EN BIT(8) /* Enable the integrated function of LED0 */
+/* bit 7:4 are reserved */
+#define XWAY_MDIO_LED_LED3_DA BIT(3) /* Direct Access to LED3 */
+#define XWAY_MDIO_LED_LED2_DA BIT(2) /* Direct Access to LED2 */
+#define XWAY_MDIO_LED_LED1_DA BIT(1) /* Direct Access to LED1 */
+#define XWAY_MDIO_LED_LED0_DA BIT(0) /* Direct Access to LED0 */
#define XWAY_MDIO_INIT_WOL BIT(15) /* Wake-On-LAN */
#define XWAY_MDIO_INIT_MSRE BIT(14)
@@ -159,6 +171,15 @@ static int xway_gphy_config_init(struct phy_device *phydev)
/* Clear all pending interrupts */
phy_read(phydev, XWAY_MDIO_ISTAT);
+ /* Ensure that integrated led function is enabled for all leds */
+ err = phy_write(phydev, XWAY_MDIO_LED,
+ XWAY_MDIO_LED_LED0_EN |
+ XWAY_MDIO_LED_LED1_EN |
+ XWAY_MDIO_LED_LED2_EN |
+ XWAY_MDIO_LED_LED3_EN);
+ if (err)
+ return err;
+
phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCH,
XWAY_MMD_LEDCH_NACS_NONE |
XWAY_MMD_LEDCH_SBF_F02HZ |
diff --git a/drivers/net/phy/marvell-88x2222.c b/drivers/net/phy/marvell-88x2222.c
index 9b9ac3ef735d..d8b31d4d2a73 100644
--- a/drivers/net/phy/marvell-88x2222.c
+++ b/drivers/net/phy/marvell-88x2222.c
@@ -473,8 +473,6 @@ static int mv2222_config_init(struct phy_device *phydev)
if (phydev->interface != PHY_INTERFACE_MODE_XAUI)
return -EINVAL;
- phydev->autoneg = AUTONEG_DISABLE;
-
return 0;
}
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index e2b2b20c0dc5..a61fde7013bd 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -978,22 +978,28 @@ static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data)
static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt)
{
- int val;
+ int val, err;
if (cnt > MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX)
return -E2BIG;
- if (!cnt)
- return phy_clear_bits(phydev, MII_M1111_PHY_EXT_CR,
- MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN);
+ if (!cnt) {
+ err = phy_clear_bits(phydev, MII_M1111_PHY_EXT_CR,
+ MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN);
+ } else {
+ val = MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN;
+ val |= FIELD_PREP(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, cnt - 1);
- val = MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN;
- val |= FIELD_PREP(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, cnt - 1);
+ err = phy_modify(phydev, MII_M1111_PHY_EXT_CR,
+ MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN |
+ MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK,
+ val);
+ }
- return phy_modify(phydev, MII_M1111_PHY_EXT_CR,
- MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN |
- MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK,
- val);
+ if (err < 0)
+ return err;
+
+ return genphy_soft_reset(phydev);
}
static int m88e1111_get_tunable(struct phy_device *phydev,
@@ -1036,22 +1042,28 @@ static int m88e1011_get_downshift(struct phy_device *phydev, u8 *data)
static int m88e1011_set_downshift(struct phy_device *phydev, u8 cnt)
{
- int val;
+ int val, err;
if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX)
return -E2BIG;
- if (!cnt)
- return phy_clear_bits(phydev, MII_M1011_PHY_SCR,
- MII_M1011_PHY_SCR_DOWNSHIFT_EN);
+ if (!cnt) {
+ err = phy_clear_bits(phydev, MII_M1011_PHY_SCR,
+ MII_M1011_PHY_SCR_DOWNSHIFT_EN);
+ } else {
+ val = MII_M1011_PHY_SCR_DOWNSHIFT_EN;
+ val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1);
- val = MII_M1011_PHY_SCR_DOWNSHIFT_EN;
- val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1);
+ err = phy_modify(phydev, MII_M1011_PHY_SCR,
+ MII_M1011_PHY_SCR_DOWNSHIFT_EN |
+ MII_M1011_PHY_SCR_DOWNSHIFT_MASK,
+ val);
+ }
- return phy_modify(phydev, MII_M1011_PHY_SCR,
- MII_M1011_PHY_SCR_DOWNSHIFT_EN |
- MII_M1011_PHY_SCR_DOWNSHIFT_MASK,
- val);
+ if (err < 0)
+ return err;
+
+ return genphy_soft_reset(phydev);
}
static int m88e1011_get_tunable(struct phy_device *phydev,
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 9bc58e64b5b7..3ef4b2841402 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -3104,7 +3104,7 @@ static void hso_free_interface(struct usb_interface *interface)
cancel_work_sync(&serial_table[i]->async_put_intf);
cancel_work_sync(&serial_table[i]->async_get_intf);
hso_serial_tty_unregister(serial);
- kref_put(&serial_table[i]->ref, hso_serial_ref_free);
+ kref_put(&serial->parent->ref, hso_serial_ref_free);
}
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
index 4456abb9a074..34bde8c87324 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
@@ -40,6 +40,7 @@ int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans,
const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD];
u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD];
struct iwl_tfh_tfd *tfd;
+ unsigned long flags;
copy_size = sizeof(struct iwl_cmd_header_wide);
cmd_size = sizeof(struct iwl_cmd_header_wide);
@@ -108,14 +109,14 @@ int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans,
goto free_dup_buf;
}
- spin_lock_bh(&txq->lock);
+ spin_lock_irqsave(&txq->lock, flags);
idx = iwl_txq_get_cmd_index(txq, txq->write_ptr);
tfd = iwl_txq_get_tfd(trans, txq, txq->write_ptr);
memset(tfd, 0, sizeof(*tfd));
if (iwl_txq_space(trans, txq) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
- spin_unlock_bh(&txq->lock);
+ spin_unlock_irqrestore(&txq->lock, flags);
IWL_ERR(trans, "No space in command queue\n");
iwl_op_mode_cmd_queue_full(trans->op_mode);
@@ -250,7 +251,7 @@ int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans,
spin_unlock(&trans_pcie->reg_lock);
out:
- spin_unlock_bh(&txq->lock);
+ spin_unlock_irqrestore(&txq->lock, flags);
free_dup_buf:
if (idx < 0)
kfree(dup_buf);
diff --git a/include/linux/dsa/sja1105.h b/include/linux/dsa/sja1105.h
index dd93735ae228..1eb84562b311 100644
--- a/include/linux/dsa/sja1105.h
+++ b/include/linux/dsa/sja1105.h
@@ -47,11 +47,12 @@ struct sja1105_tagger_data {
};
struct sja1105_skb_cb {
+ struct sk_buff *clone;
u32 meta_tstamp;
};
#define SJA1105_SKB_CB(skb) \
- ((struct sja1105_skb_cb *)DSA_SKB_CB_PRIV(skb))
+ ((struct sja1105_skb_cb *)((skb)->cb))
struct sja1105_port {
u16 subvlan_map[DSA_8021Q_N_SUBVLAN];
diff --git a/include/linux/mdio-bitbang.h b/include/linux/mdio-bitbang.h
index aca4dc037b70..373630fe5c28 100644
--- a/include/linux/mdio-bitbang.h
+++ b/include/linux/mdio-bitbang.h
@@ -33,6 +33,9 @@ struct mdiobb_ops {
struct mdiobb_ctrl {
const struct mdiobb_ops *ops;
+ unsigned int override_op_c22;
+ u8 op_c22_read;
+ u8 op_c22_write;
};
int mdiobb_read(struct mii_bus *bus, int phy, int reg);
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index d4c14257db5d..515ce53aa20d 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -7,21 +7,26 @@
#include <net/netlink.h>
#include <uapi/linux/netfilter/nfnetlink.h>
+struct nfnl_info {
+ struct net *net;
+ struct sock *sk;
+ const struct nlmsghdr *nlh;
+ struct netlink_ext_ack *extack;
+};
+
+enum nfnl_callback_type {
+ NFNL_CB_UNSPEC = 0,
+ NFNL_CB_MUTEX,
+ NFNL_CB_RCU,
+ NFNL_CB_BATCH,
+};
+
struct nfnl_callback {
- int (*call)(struct net *net, struct sock *nl, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack);
- int (*call_rcu)(struct net *net, struct sock *nl, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack);
- int (*call_batch)(struct net *net, struct sock *nl, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack);
- const struct nla_policy *policy; /* netlink attribute policy */
- const u_int16_t attr_count; /* number of nlattr's */
+ int (*call)(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const cda[]);
+ const struct nla_policy *policy;
+ enum nfnl_callback_type type;
+ __u16 attr_count;
};
enum nfnl_abort_action {
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 8ec48466410a..07c6ad8f2a02 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -158,7 +158,7 @@ struct xt_match {
/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_mtdtor_param *);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src);
@@ -169,7 +169,7 @@ struct xt_match {
const char *table;
unsigned int matchsize;
unsigned int usersize;
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
unsigned int compatsize;
#endif
unsigned int hooks;
@@ -199,7 +199,7 @@ struct xt_target {
/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_tgdtor_param *);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src);
@@ -210,7 +210,7 @@ struct xt_target {
const char *table;
unsigned int targetsize;
unsigned int usersize;
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
unsigned int compatsize;
#endif
unsigned int hooks;
@@ -229,6 +229,9 @@ struct xt_table {
/* Man behind the curtain... */
struct xt_table_info *private;
+ /* hook ops that register the table with the netfilter core */
+ struct nf_hook_ops *ops;
+
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
@@ -322,6 +325,7 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision);
int xt_find_revision(u8 af, const char *name, u8 revision, int target,
int *err);
+struct xt_table *xt_find_table(struct net *net, u8 af, const char *name);
struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
const char *name);
struct xt_table *xt_request_find_table_lock(struct net *net, u_int8_t af,
@@ -448,7 +452,7 @@ xt_get_per_cpu_counter(struct xt_counters *cnt, unsigned int cpu)
struct nf_hook_ops *xt_hook_ops_alloc(const struct xt_table *, nf_hookfn *);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h>
struct compat_xt_entry_match {
@@ -529,5 +533,5 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,
unsigned int target_offset,
unsigned int next_offset);
-#endif /* CONFIG_COMPAT */
+#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
#endif /* _X_TABLES_H */
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
index 26a13294318c..2aab9612f6ab 100644
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -51,15 +51,15 @@ struct arpt_error {
extern void *arpt_alloc_initial_table(const struct xt_table *);
int arpt_register_table(struct net *net, const struct xt_table *table,
const struct arpt_replace *repl,
- const struct nf_hook_ops *ops, struct xt_table **res);
-void arpt_unregister_table(struct net *net, struct xt_table *table);
-void arpt_unregister_table_pre_exit(struct net *net, struct xt_table *table,
+ const struct nf_hook_ops *ops);
+void arpt_unregister_table(struct net *net, const char *name);
+void arpt_unregister_table_pre_exit(struct net *net, const char *name,
const struct nf_hook_ops *ops);
extern unsigned int arpt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state,
struct xt_table *table);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h>
struct compat_arpt_entry {
diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
index 3a956145a25c..a8178253ce53 100644
--- a/include/linux/netfilter_bridge/ebtables.h
+++ b/include/linux/netfilter_bridge/ebtables.h
@@ -100,6 +100,7 @@ struct ebt_table {
unsigned int valid_hooks);
/* the data used by the kernel */
struct ebt_table_info *private;
+ struct nf_hook_ops *ops;
struct module *me;
};
@@ -108,11 +109,9 @@ struct ebt_table {
extern int ebt_register_table(struct net *net,
const struct ebt_table *table,
- const struct nf_hook_ops *ops,
- struct ebt_table **res);
-extern void ebt_unregister_table(struct net *net, struct ebt_table *table);
-void ebt_unregister_table_pre_exit(struct net *net, const char *tablename,
- const struct nf_hook_ops *ops);
+ const struct nf_hook_ops *ops);
+extern void ebt_unregister_table(struct net *net, const char *tablename);
+void ebt_unregister_table_pre_exit(struct net *net, const char *tablename);
extern unsigned int ebt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state,
struct ebt_table *table);
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index c4676d6feeff..8d09bfe850dc 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -24,15 +24,10 @@
int ipt_register_table(struct net *net, const struct xt_table *table,
const struct ipt_replace *repl,
- const struct nf_hook_ops *ops, struct xt_table **res);
-
-void ipt_unregister_table_pre_exit(struct net *net, struct xt_table *table,
const struct nf_hook_ops *ops);
-void ipt_unregister_table_exit(struct net *net, struct xt_table *table);
-
-void ipt_unregister_table(struct net *net, struct xt_table *table,
- const struct nf_hook_ops *ops);
+void ipt_unregister_table_pre_exit(struct net *net, const char *name);
+void ipt_unregister_table_exit(struct net *net, const char *name);
/* Standard entry. */
struct ipt_standard {
@@ -72,7 +67,7 @@ extern unsigned int ipt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state,
struct xt_table *table);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h>
struct compat_ipt_entry {
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 1547d5f9ae06..79e73fd7d965 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -26,17 +26,14 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *);
int ip6t_register_table(struct net *net, const struct xt_table *table,
const struct ip6t_replace *repl,
- const struct nf_hook_ops *ops, struct xt_table **res);
-void ip6t_unregister_table(struct net *net, struct xt_table *table,
- const struct nf_hook_ops *ops);
-void ip6t_unregister_table_pre_exit(struct net *net, struct xt_table *table,
- const struct nf_hook_ops *ops);
-void ip6t_unregister_table_exit(struct net *net, struct xt_table *table);
+ const struct nf_hook_ops *ops);
+void ip6t_unregister_table_pre_exit(struct net *net, const char *name);
+void ip6t_unregister_table_exit(struct net *net, const char *name);
extern unsigned int ip6t_do_table(struct sk_buff *skb,
const struct nf_hook_state *state,
struct xt_table *table);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h>
struct compat_ip6t_entry {
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 385894b4a8bb..b8fc5c53ba6f 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -85,7 +85,7 @@ struct mmsghdr {
/*
* POSIX 1003.1g - ancillary data object information
- * Ancillary data consits of a sequence of pairs of
+ * Ancillary data consists of a sequence of pairs of
* (cmsghdr, cmsg_data[])
*/
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 18f783dcd55f..78ea3e332688 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -233,7 +233,6 @@ void ipv6_mc_unmap(struct inet6_dev *idev);
void ipv6_mc_remap(struct inet6_dev *idev);
void ipv6_mc_init_dev(struct inet6_dev *idev);
void ipv6_mc_destroy_dev(struct inet6_dev *idev);
-int ipv6_mc_check_icmpv6(struct sk_buff *skb);
int ipv6_mc_check_mld(struct sk_buff *skb);
void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp);
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 507082959aa4..e1a2610a0e06 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -117,20 +117,6 @@ struct dsa_netdevice_ops {
#define MODULE_ALIAS_DSA_TAG_DRIVER(__proto) \
MODULE_ALIAS(DSA_TAG_DRIVER_ALIAS __stringify(__proto##_VALUE))
-struct dsa_skb_cb {
- struct sk_buff *clone;
-};
-
-struct __dsa_skb_cb {
- struct dsa_skb_cb cb;
- u8 priv[48 - sizeof(struct dsa_skb_cb)];
-};
-
-#define DSA_SKB_CB(skb) ((struct dsa_skb_cb *)((skb)->cb))
-
-#define DSA_SKB_CB_PRIV(skb) \
- ((void *)(skb)->cb + offsetof(struct __dsa_skb_cb, priv))
-
struct dsa_switch_tree {
struct list_head list;
@@ -740,8 +726,8 @@ struct dsa_switch_ops {
struct ifreq *ifr);
int (*port_hwtstamp_set)(struct dsa_switch *ds, int port,
struct ifreq *ifr);
- bool (*port_txtstamp)(struct dsa_switch *ds, int port,
- struct sk_buff *clone, unsigned int type);
+ void (*port_txtstamp)(struct dsa_switch *ds, int port,
+ struct sk_buff *skb);
bool (*port_rxtstamp)(struct dsa_switch *ds, int port,
struct sk_buff *skb, unsigned int type);
diff --git a/include/net/netfilter/ipv4/nf_defrag_ipv4.h b/include/net/netfilter/ipv4/nf_defrag_ipv4.h
index bcbd724cc048..7fda9ce9f694 100644
--- a/include/net/netfilter/ipv4/nf_defrag_ipv4.h
+++ b/include/net/netfilter/ipv4/nf_defrag_ipv4.h
@@ -3,6 +3,7 @@
#define _NF_DEFRAG_IPV4_H
struct net;
-int nf_defrag_ipv4_enable(struct net *);
+int nf_defrag_ipv4_enable(struct net *net);
+void nf_defrag_ipv4_disable(struct net *net);
#endif /* _NF_DEFRAG_IPV4_H */
diff --git a/include/net/netfilter/ipv6/nf_defrag_ipv6.h b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
index ece923e2035b..0fd8a4159662 100644
--- a/include/net/netfilter/ipv6/nf_defrag_ipv6.h
+++ b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
@@ -5,7 +5,8 @@
#include <linux/skbuff.h>
#include <linux/types.h>
-int nf_defrag_ipv6_enable(struct net *);
+int nf_defrag_ipv6_enable(struct net *net);
+void nf_defrag_ipv6_disable(struct net *net);
int nf_ct_frag6_init(void);
void nf_ct_frag6_cleanup(void);
diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h
index 0d412dd63707..987111ae5240 100644
--- a/include/net/netfilter/nf_nat.h
+++ b/include/net/netfilter/nf_nat.h
@@ -104,8 +104,6 @@ unsigned int
nf_nat_inet_fn(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state);
-int nf_xfrm_me_harder(struct net *n, struct sk_buff *s, unsigned int family);
-
static inline int nf_nat_initialized(struct nf_conn *ct,
enum nf_nat_manip_type manip)
{
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 4a75da2a2e1d..27eeb613bb4e 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -13,6 +13,7 @@
#include <net/netfilter/nf_flow_table.h>
#include <net/netlink.h>
#include <net/flow_offload.h>
+#include <net/netns/generic.h>
#define NFT_MAX_HOOKS (NF_INET_INGRESS + 1)
@@ -496,6 +497,7 @@ struct nft_set {
u8 dlen;
u8 num_exprs;
struct nft_expr *exprs[NFT_SET_EXPR_MAX];
+ struct list_head catchall_list;
unsigned char data[]
__attribute__((aligned(__alignof__(u64))));
};
@@ -521,6 +523,10 @@ struct nft_set *nft_set_lookup_global(const struct net *net,
const struct nlattr *nla_set_id,
u8 genmask);
+struct nft_set_ext *nft_set_catchall_lookup(const struct net *net,
+ const struct nft_set *set);
+void *nft_set_catchall_gc(const struct nft_set *set);
+
static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
{
return set->gc_int ? msecs_to_jiffies(set->gc_int) : HZ;
@@ -1580,4 +1586,11 @@ struct nftables_pernet {
u8 validate_state;
};
+extern unsigned int nf_tables_net_id;
+
+static inline struct nftables_pernet *nft_pernet(const struct net *net)
+{
+ return net_generic(net, nf_tables_net_id);
+}
+
#endif /* _NET_NF_TABLES_H */
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 87e1612497ea..f6af8d96d3c6 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -76,16 +76,6 @@ struct netns_ipv4 {
struct inet_peer_base *peers;
struct sock * __percpu *tcp_sk;
struct fqdir *fqdir;
-#ifdef CONFIG_NETFILTER
- struct xt_table *iptable_filter;
- struct xt_table *iptable_mangle;
- struct xt_table *iptable_raw;
- struct xt_table *arptable_filter;
-#ifdef CONFIG_SECURITY
- struct xt_table *iptable_security;
-#endif
- struct xt_table *nat_table;
-#endif
u8 sysctl_icmp_echo_ignore_all;
u8 sysctl_icmp_echo_enable_probe;
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 808f0f79ea9c..6153c8067009 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -63,15 +63,6 @@ struct netns_ipv6 {
struct ipv6_devconf *devconf_dflt;
struct inet_peer_base *peers;
struct fqdir *fqdir;
-#ifdef CONFIG_NETFILTER
- struct xt_table *ip6table_filter;
- struct xt_table *ip6table_mangle;
- struct xt_table *ip6table_raw;
-#ifdef CONFIG_SECURITY
- struct xt_table *ip6table_security;
-#endif
- struct xt_table *ip6table_nat;
-#endif
struct fib6_info *fib6_null_entry;
struct rt6_info *ip6_null_entry;
struct rt6_statistics *rt6_stats;
diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
index 83c8ea2e87a6..d02316ec2906 100644
--- a/include/net/netns/x_tables.h
+++ b/include/net/netns/x_tables.h
@@ -5,16 +5,8 @@
#include <linux/list.h>
#include <linux/netfilter_defs.h>
-struct ebt_table;
-
struct netns_xt {
bool notrack_deprecated_warning;
bool clusterip_deprecated_warning;
-#if defined(CONFIG_BRIDGE_NF_EBTABLES) || \
- defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE)
- struct ebt_table *broute_table;
- struct ebt_table *frame_filter;
- struct ebt_table *frame_nat;
-#endif
};
#endif
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 68cdc7ceaf4d..2f5ce4d4fdbf 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -689,6 +689,15 @@ struct ocelot_policer {
u32 burst; /* bytes */
};
+struct ocelot_skb_cb {
+ struct sk_buff *clone;
+ u8 ptp_cmd;
+ u8 ts_id;
+};
+
+#define OCELOT_SKB_CB(skb) \
+ ((struct ocelot_skb_cb *)((skb)->cb))
+
#define ocelot_read_ix(ocelot, reg, gi, ri) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
#define ocelot_read_gix(ocelot, reg, gi) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi))
#define ocelot_read_rix(ocelot, reg, ri) __ocelot_read_ix(ocelot, reg, reg##_RSZ * (ri))
@@ -740,15 +749,16 @@ u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target,
void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
u32 val, u32 reg, u32 offset);
-/* Packet I/O */
#if IS_ENABLED(CONFIG_MSCC_OCELOT_SWITCH_LIB)
+/* Packet I/O */
bool ocelot_can_inject(struct ocelot *ocelot, int grp);
void ocelot_port_inject_frame(struct ocelot *ocelot, int port, int grp,
u32 rew_op, struct sk_buff *skb);
int ocelot_xtr_poll_frame(struct ocelot *ocelot, int grp, struct sk_buff **skb);
void ocelot_drain_cpu_queue(struct ocelot *ocelot, int grp);
+u32 ocelot_ptp_rew_op(struct sk_buff *skb);
#else
static inline bool ocelot_can_inject(struct ocelot *ocelot, int grp)
@@ -772,6 +782,10 @@ static inline void ocelot_drain_cpu_queue(struct ocelot *ocelot, int grp)
{
}
+static inline u32 ocelot_ptp_rew_op(struct sk_buff *skb)
+{
+ return 0;
+}
#endif
/* Hardware initialization */
@@ -820,8 +834,9 @@ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid);
int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr);
int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr);
-void ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port,
- struct sk_buff *clone);
+int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port,
+ struct sk_buff *skb,
+ struct sk_buff **clone);
void ocelot_get_txtstamp(struct ocelot *ocelot);
void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu);
int ocelot_get_max_mtu(struct ocelot *ocelot, int port);
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 79bab7a36b30..1fb4ca18ffbb 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -398,9 +398,11 @@ enum nft_set_attributes {
* enum nft_set_elem_flags - nf_tables set element flags
*
* @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval
+ * @NFT_SET_ELEM_CATCHALL: special catch-all element
*/
enum nft_set_elem_flags {
NFT_SET_ELEM_INTERVAL_END = 0x1,
+ NFT_SET_ELEM_CATCHALL = 0x2,
};
/**
@@ -1014,11 +1016,13 @@ enum nft_rt_attributes {
*
* @NFTA_SOCKET_KEY: socket key to match
* @NFTA_SOCKET_DREG: destination register
+ * @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2)
*/
enum nft_socket_attributes {
NFTA_SOCKET_UNSPEC,
NFTA_SOCKET_KEY,
NFTA_SOCKET_DREG,
+ NFTA_SOCKET_LEVEL,
__NFTA_SOCKET_MAX
};
#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1)
@@ -1029,11 +1033,13 @@ enum nft_socket_attributes {
* @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option
* @NFT_SOCKET_MARK: Value of the socket mark
* @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0)
+ * @NFT_SOCKET_CGROUPV2: Match on cgroups version 2
*/
enum nft_socket_keys {
NFT_SOCKET_TRANSPARENT,
NFT_SOCKET_MARK,
NFT_SOCKET_WILDCARD,
+ NFT_SOCKET_CGROUPV2,
__NFT_SOCKET_MAX
};
#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1)
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 8b644113715e..fb3d3262dc1a 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -71,6 +71,9 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg,
if (array == NULL)
return -ENOBUFS;
+ /* paired with smp_rmb() in __vlan_group_get_device() */
+ smp_wmb();
+
vg->vlan_devices_arrays[pidx][vidx] = array;
return 0;
}
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 953405362795..fa3ad3d4d58c 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -57,6 +57,10 @@ static inline struct net_device *__vlan_group_get_device(struct vlan_group *vg,
array = vg->vlan_devices_arrays[pidx]
[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
+
+ /* paired with smp_wmb() in vlan_group_prealloc_vid() */
+ smp_rmb();
+
return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL;
}
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 2883601d5c8b..226bb05c3b42 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -3159,25 +3159,14 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
}
#if IS_ENABLED(CONFIG_IPV6)
-static int br_ip6_multicast_mrd_rcv(struct net_bridge *br,
- struct net_bridge_port *port,
- struct sk_buff *skb)
+static void br_ip6_multicast_mrd_rcv(struct net_bridge *br,
+ struct net_bridge_port *port,
+ struct sk_buff *skb)
{
- int ret;
-
- if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6)
- return -ENOMSG;
-
- ret = ipv6_mc_check_icmpv6(skb);
- if (ret < 0)
- return ret;
-
if (icmp6_hdr(skb)->icmp6_type != ICMPV6_MRDISC_ADV)
- return -ENOMSG;
+ return;
br_multicast_mark_router(br, port);
-
- return 0;
}
static int br_multicast_ipv6_rcv(struct net_bridge *br,
@@ -3191,18 +3180,12 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
err = ipv6_mc_check_mld(skb);
- if (err == -ENOMSG) {
+ if (err == -ENOMSG || err == -ENODATA) {
if (!ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr))
BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
-
- if (ipv6_addr_is_all_snoopers(&ipv6_hdr(skb)->daddr)) {
- err = br_ip6_multicast_mrd_rcv(br, port, skb);
-
- if (err < 0 && err != -ENOMSG) {
- br_multicast_err_count(br, port, skb->protocol);
- return err;
- }
- }
+ if (err == -ENODATA &&
+ ipv6_addr_is_all_snoopers(&ipv6_hdr(skb)->daddr))
+ br_ip6_multicast_mrd_rcv(br, port, skb);
return 0;
} else if (err < 0) {
diff --git a/net/bridge/netfilter/ebt_limit.c b/net/bridge/netfilter/ebt_limit.c
index fa199556e122..e16183bd1bb8 100644
--- a/net/bridge/netfilter/ebt_limit.c
+++ b/net/bridge/netfilter/ebt_limit.c
@@ -87,7 +87,7 @@ static int ebt_limit_mt_check(const struct xt_mtchk_param *par)
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/*
* no conversion function needed --
* only avg/burst have meaningful values in userspace.
@@ -107,7 +107,7 @@ static struct xt_match ebt_limit_mt_reg __read_mostly = {
.checkentry = ebt_limit_mt_check,
.matchsize = sizeof(struct ebt_limit_info),
.usersize = offsetof(struct ebt_limit_info, prev),
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct ebt_compat_limit_info),
#endif
.me = THIS_MODULE,
diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
index 21fd3d3d77f6..8cf653c72fd8 100644
--- a/net/bridge/netfilter/ebt_mark.c
+++ b/net/bridge/netfilter/ebt_mark.c
@@ -53,7 +53,7 @@ static int ebt_mark_tg_check(const struct xt_tgchk_param *par)
return -EINVAL;
return 0;
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ebt_mark_t_info {
compat_ulong_t mark;
compat_uint_t target;
@@ -87,7 +87,7 @@ static struct xt_target ebt_mark_tg_reg __read_mostly = {
.target = ebt_mark_tg,
.checkentry = ebt_mark_tg_check,
.targetsize = sizeof(struct ebt_mark_t_info),
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ebt_mark_t_info),
.compat_from_user = mark_tg_compat_from_user,
.compat_to_user = mark_tg_compat_to_user,
diff --git a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c
index 81fb59dec499..5872e73c741e 100644
--- a/net/bridge/netfilter/ebt_mark_m.c
+++ b/net/bridge/netfilter/ebt_mark_m.c
@@ -37,7 +37,7 @@ static int ebt_mark_mt_check(const struct xt_mtchk_param *par)
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ebt_mark_m_info {
compat_ulong_t mark, mask;
uint8_t invert, bitmask;
@@ -75,7 +75,7 @@ static struct xt_match ebt_mark_mt_reg __read_mostly = {
.match = ebt_mark_mt,
.checkentry = ebt_mark_mt_check,
.matchsize = sizeof(struct ebt_mark_m_info),
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ebt_mark_m_info),
.compat_from_user = mark_mt_compat_from_user,
.compat_to_user = mark_mt_compat_to_user,
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index 32bc2821027f..020b1487ee0c 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -66,8 +66,7 @@ static unsigned int ebt_broute(void *priv, struct sk_buff *skb,
NFPROTO_BRIDGE, s->in, NULL, NULL,
s->net, NULL);
- ret = ebt_do_table(skb, &state, state.net->xt.broute_table);
-
+ ret = ebt_do_table(skb, &state, priv);
if (ret != NF_DROP)
return ret;
@@ -101,18 +100,17 @@ static const struct nf_hook_ops ebt_ops_broute = {
static int __net_init broute_net_init(struct net *net)
{
- return ebt_register_table(net, &broute_table, &ebt_ops_broute,
- &net->xt.broute_table);
+ return ebt_register_table(net, &broute_table, &ebt_ops_broute);
}
static void __net_exit broute_net_pre_exit(struct net *net)
{
- ebt_unregister_table_pre_exit(net, "broute", &ebt_ops_broute);
+ ebt_unregister_table_pre_exit(net, "broute");
}
static void __net_exit broute_net_exit(struct net *net)
{
- ebt_unregister_table(net, net->xt.broute_table);
+ ebt_unregister_table(net, "broute");
}
static struct pernet_operations broute_net_ops = {
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index bcf982e12f16..8ec0b3736803 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -59,34 +59,27 @@ static const struct ebt_table frame_filter = {
};
static unsigned int
-ebt_in_hook(void *priv, struct sk_buff *skb,
- const struct nf_hook_state *state)
+ebt_filter_hook(void *priv, struct sk_buff *skb,
+ const struct nf_hook_state *state)
{
- return ebt_do_table(skb, state, state->net->xt.frame_filter);
-}
-
-static unsigned int
-ebt_out_hook(void *priv, struct sk_buff *skb,
- const struct nf_hook_state *state)
-{
- return ebt_do_table(skb, state, state->net->xt.frame_filter);
+ return ebt_do_table(skb, state, priv);
}
static const struct nf_hook_ops ebt_ops_filter[] = {
{
- .hook = ebt_in_hook,
+ .hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_IN,
.priority = NF_BR_PRI_FILTER_BRIDGED,
},
{
- .hook = ebt_in_hook,
+ .hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_FORWARD,
.priority = NF_BR_PRI_FILTER_BRIDGED,
},
{
- .hook = ebt_out_hook,
+ .hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_OUT,
.priority = NF_BR_PRI_FILTER_OTHER,
@@ -95,18 +88,17 @@ static const struct nf_hook_ops ebt_ops_filter[] = {
static int __net_init frame_filter_net_init(struct net *net)
{
- return ebt_register_table(net, &frame_filter, ebt_ops_filter,
- &net->xt.frame_filter);
+ return ebt_register_table(net, &frame_filter, ebt_ops_filter);
}
static void __net_exit frame_filter_net_pre_exit(struct net *net)
{
- ebt_unregister_table_pre_exit(net, "filter", ebt_ops_filter);
+ ebt_unregister_table_pre_exit(net, "filter");
}
static void __net_exit frame_filter_net_exit(struct net *net)
{
- ebt_unregister_table(net, net->xt.frame_filter);
+ ebt_unregister_table(net, "filter");
}
static struct pernet_operations frame_filter_net_ops = {
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index 0d092773f816..7c8a1064a531 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -58,35 +58,27 @@ static const struct ebt_table frame_nat = {
.me = THIS_MODULE,
};
-static unsigned int
-ebt_nat_in(void *priv, struct sk_buff *skb,
- const struct nf_hook_state *state)
+static unsigned int ebt_nat_hook(void *priv, struct sk_buff *skb,
+ const struct nf_hook_state *state)
{
- return ebt_do_table(skb, state, state->net->xt.frame_nat);
-}
-
-static unsigned int
-ebt_nat_out(void *priv, struct sk_buff *skb,
- const struct nf_hook_state *state)
-{
- return ebt_do_table(skb, state, state->net->xt.frame_nat);
+ return ebt_do_table(skb, state, priv);
}
static const struct nf_hook_ops ebt_ops_nat[] = {
{
- .hook = ebt_nat_out,
+ .hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_OUT,
.priority = NF_BR_PRI_NAT_DST_OTHER,
},
{
- .hook = ebt_nat_out,
+ .hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_POST_ROUTING,
.priority = NF_BR_PRI_NAT_SRC,
},
{
- .hook = ebt_nat_in,
+ .hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_PRE_ROUTING,
.priority = NF_BR_PRI_NAT_DST_BRIDGED,
@@ -95,18 +87,17 @@ static const struct nf_hook_ops ebt_ops_nat[] = {
static int __net_init frame_nat_net_init(struct net *net)
{
- return ebt_register_table(net, &frame_nat, ebt_ops_nat,
- &net->xt.frame_nat);
+ return ebt_register_table(net, &frame_nat, ebt_ops_nat);
}
static void __net_exit frame_nat_net_pre_exit(struct net *net)
{
- ebt_unregister_table_pre_exit(net, "nat", ebt_ops_nat);
+ ebt_unregister_table_pre_exit(net, "nat");
}
static void __net_exit frame_nat_net_exit(struct net *net)
{
- ebt_unregister_table(net, net->xt.frame_nat);
+ ebt_unregister_table(net, "nat");
}
static struct pernet_operations frame_nat_net_ops = {
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 96d789c8d1c7..f022deb3721e 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -47,7 +47,7 @@ struct ebt_pernet {
static unsigned int ebt_pernet_id __read_mostly;
static DEFINE_MUTEX(ebt_mutex);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void ebt_standard_compat_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
@@ -73,7 +73,7 @@ static struct xt_target ebt_standard_target = {
.revision = 0,
.family = NFPROTO_BRIDGE,
.targetsize = sizeof(int),
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t),
.compat_from_user = ebt_standard_compat_from_user,
.compat_to_user = ebt_standard_compat_to_user,
@@ -1136,15 +1136,18 @@ static void __ebt_unregister_table(struct net *net, struct ebt_table *table)
vfree(table->private->entries);
ebt_free_table_info(table->private);
vfree(table->private);
+ kfree(table->ops);
kfree(table);
}
int ebt_register_table(struct net *net, const struct ebt_table *input_table,
- const struct nf_hook_ops *ops, struct ebt_table **res)
+ const struct nf_hook_ops *template_ops)
{
struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id);
struct ebt_table_info *newinfo;
struct ebt_table *t, *table;
+ struct nf_hook_ops *ops;
+ unsigned int num_ops;
struct ebt_replace_kernel *repl;
int ret, i, countersize;
void *p;
@@ -1213,15 +1216,31 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table,
ret = -ENOENT;
goto free_unlock;
}
+
+ num_ops = hweight32(table->valid_hooks);
+ if (num_ops == 0) {
+ ret = -EINVAL;
+ goto free_unlock;
+ }
+
+ ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
+ if (!ops) {
+ ret = -ENOMEM;
+ if (newinfo->nentries)
+ module_put(table->me);
+ goto free_unlock;
+ }
+
+ for (i = 0; i < num_ops; i++)
+ ops[i].priv = table;
+
list_add(&table->list, &ebt_net->tables);
mutex_unlock(&ebt_mutex);
- WRITE_ONCE(*res, table);
- ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
- if (ret) {
+ table->ops = ops;
+ ret = nf_register_net_hooks(net, ops, num_ops);
+ if (ret)
__ebt_unregister_table(net, table);
- *res = NULL;
- }
audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries,
AUDIT_XT_OP_REGISTER, GFP_KERNEL);
@@ -1257,18 +1276,21 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name)
return NULL;
}
-void ebt_unregister_table_pre_exit(struct net *net, const char *name, const struct nf_hook_ops *ops)
+void ebt_unregister_table_pre_exit(struct net *net, const char *name)
{
struct ebt_table *table = __ebt_find_table(net, name);
if (table)
- nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
+ nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
}
EXPORT_SYMBOL(ebt_unregister_table_pre_exit);
-void ebt_unregister_table(struct net *net, struct ebt_table *table)
+void ebt_unregister_table(struct net *net, const char *name)
{
- __ebt_unregister_table(net, table);
+ struct ebt_table *table = __ebt_find_table(net, name);
+
+ if (table)
+ __ebt_unregister_table(net, table);
}
/* userspace just supplied us with counters */
@@ -1480,7 +1502,7 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user,
ebt_entry_to_user, entries, tmp.entries);
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* 32 bit-userspace compatibility definitions. */
struct compat_ebt_replace {
char name[EBT_TABLE_MAXNAMELEN];
@@ -2345,7 +2367,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* try real handler in case userland supplied needed padding */
if (in_compat_syscall() &&
((cmd != EBT_SO_GET_INFO && cmd != EBT_SO_GET_INIT_INFO) ||
@@ -2412,7 +2434,7 @@ static int do_ebt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
switch (cmd) {
case EBT_SO_SET_ENTRIES:
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(net, arg, len);
else
@@ -2420,7 +2442,7 @@ static int do_ebt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
ret = do_replace(net, arg, len);
break;
case EBT_SO_SET_COUNTERS:
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_update_counters(net, arg, len);
else
diff --git a/net/can/proc.c b/net/can/proc.c
index b15760b5c1cc..d1fe49e6f16d 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -205,8 +205,10 @@ static void can_print_recv_banner(struct seq_file *m)
* can1. 00000000 00000000 00000000
* ....... 0 tp20
*/
- seq_puts(m, " device can_id can_mask function"
- " userdata matches ident\n");
+ if (IS_ENABLED(CONFIG_64BIT))
+ seq_puts(m, " device can_id can_mask function userdata matches ident\n");
+ else
+ seq_puts(m, " device can_id can_mask function userdata matches ident\n");
}
static int can_stats_proc_show(struct seq_file *m, void *v)
diff --git a/net/core/dev.c b/net/core/dev.c
index eed028aec6a4..222b1d322c96 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5966,7 +5966,7 @@ static void gro_list_prepare(const struct list_head *head,
}
}
-static void skb_gro_reset_offset(struct sk_buff *skb)
+static inline void skb_gro_reset_offset(struct sk_buff *skb, u32 nhoff)
{
const struct skb_shared_info *pinfo = skb_shinfo(skb);
const skb_frag_t *frag0 = &pinfo->frags[0];
@@ -5977,7 +5977,7 @@ static void skb_gro_reset_offset(struct sk_buff *skb)
if (!skb_headlen(skb) && pinfo->nr_frags &&
!PageHighMem(skb_frag_page(frag0)) &&
- (!NET_IP_ALIGN || !(skb_frag_off(frag0) & 3))) {
+ (!NET_IP_ALIGN || !((skb_frag_off(frag0) + nhoff) & 3))) {
NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0);
NAPI_GRO_CB(skb)->frag0_len = min_t(unsigned int,
skb_frag_size(frag0),
@@ -6195,7 +6195,7 @@ gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
skb_mark_napi_id(skb, napi);
trace_napi_gro_receive_entry(skb);
- skb_gro_reset_offset(skb);
+ skb_gro_reset_offset(skb, 0);
ret = napi_skb_finish(napi, skb, dev_gro_receive(napi, skb));
trace_napi_gro_receive_exit(ret);
@@ -6284,7 +6284,7 @@ static struct sk_buff *napi_frags_skb(struct napi_struct *napi)
napi->skb = NULL;
skb_reset_mac_header(skb);
- skb_gro_reset_offset(skb);
+ skb_gro_reset_offset(skb, hlen);
if (unlikely(skb_gro_header_hard(skb, hlen))) {
eth = skb_gro_header_slow(skb, hlen, 0);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 8379719d1dce..98f20efbfadf 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -131,6 +131,9 @@ static void neigh_update_gc_list(struct neighbour *n)
write_lock_bh(&n->tbl->lock);
write_lock(&n->lock);
+ if (n->dead)
+ goto out;
+
/* remove from the gc list if new state is permanent or if neighbor
* is externally learned; otherwise entry should be on the gc list
*/
@@ -147,6 +150,7 @@ static void neigh_update_gc_list(struct neighbour *n)
atomic_inc(&n->tbl->gc_entries);
}
+out:
write_unlock(&n->lock);
write_unlock_bh(&n->tbl->lock);
}
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index cbc2bd643ab2..5baba7021427 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -111,6 +111,8 @@ config NET_DSA_TAG_RTL4_A
config NET_DSA_TAG_OCELOT
tristate "Tag driver for Ocelot family of switches, using NPI port"
+ depends on MSCC_OCELOT_SWITCH_LIB || \
+ (MSCC_OCELOT_SWITCH_LIB=n && COMPILE_TEST)
select PACKING
help
Say Y or M if you want to enable NPI tagging for the Ocelot switches
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 77b33bd161b8..8c0f3c6ab365 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -20,7 +20,6 @@
#include <linux/if_bridge.h>
#include <linux/if_hsr.h>
#include <linux/netpoll.h>
-#include <linux/ptp_classify.h>
#include "dsa_priv.h"
@@ -556,26 +555,14 @@ static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p,
struct sk_buff *skb)
{
struct dsa_switch *ds = p->dp->ds;
- struct sk_buff *clone;
- unsigned int type;
- type = ptp_classify_raw(skb);
- if (type == PTP_CLASS_NONE)
+ if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
return;
if (!ds->ops->port_txtstamp)
return;
- clone = skb_clone_sk(skb);
- if (!clone)
- return;
-
- if (ds->ops->port_txtstamp(ds, p->dp->index, clone, type)) {
- DSA_SKB_CB(skb)->clone = clone;
- return;
- }
-
- kfree_skb(clone);
+ ds->ops->port_txtstamp(ds, p->dp->index, skb);
}
netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev)
@@ -627,11 +614,9 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
dev_sw_netstats_tx_add(dev, 1, skb->len);
- DSA_SKB_CB(skb)->clone = NULL;
+ memset(skb->cb, 0, sizeof(skb->cb));
- /* Identify PTP protocol packets, clone them, and pass them to the
- * switch driver
- */
+ /* Handle tx timestamp if any */
dsa_skb_tx_timestamp(p, skb);
if (dsa_realloc_skb(skb, dev)) {
diff --git a/net/dsa/tag_ocelot.c b/net/dsa/tag_ocelot.c
index f9df9cac81c5..91f0fd1242cd 100644
--- a/net/dsa/tag_ocelot.c
+++ b/net/dsa/tag_ocelot.c
@@ -5,33 +5,14 @@
#include <soc/mscc/ocelot.h>
#include "dsa_priv.h"
-static void ocelot_xmit_ptp(struct dsa_port *dp, void *injection,
- struct sk_buff *clone)
-{
- struct ocelot *ocelot = dp->ds->priv;
- struct ocelot_port *ocelot_port;
- u64 rew_op;
-
- ocelot_port = ocelot->ports[dp->index];
- rew_op = ocelot_port->ptp_cmd;
-
- /* Retrieve timestamp ID populated inside skb->cb[0] of the
- * clone by ocelot_port_add_txtstamp_skb
- */
- if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
- rew_op |= clone->cb[0] << 3;
-
- ocelot_ifh_set_rew_op(injection, rew_op);
-}
-
static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev,
__be32 ifh_prefix, void **ifh)
{
struct dsa_port *dp = dsa_slave_to_port(netdev);
- struct sk_buff *clone = DSA_SKB_CB(skb)->clone;
struct dsa_switch *ds = dp->ds;
void *injection;
__be32 *prefix;
+ u32 rew_op = 0;
injection = skb_push(skb, OCELOT_TAG_LEN);
prefix = skb_push(skb, OCELOT_SHORT_PREFIX_LEN);
@@ -42,9 +23,9 @@ static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev,
ocelot_ifh_set_src(injection, ds->num_ports);
ocelot_ifh_set_qos_class(injection, skb->priority);
- /* TX timestamping was requested */
- if (clone)
- ocelot_xmit_ptp(dp, injection, clone);
+ rew_op = ocelot_ptp_rew_op(skb);
+ if (rew_op)
+ ocelot_ifh_set_rew_op(injection, rew_op);
*ifh = injection;
}
diff --git a/net/dsa/tag_ocelot_8021q.c b/net/dsa/tag_ocelot_8021q.c
index 5f3e8e124a82..62a93303bd63 100644
--- a/net/dsa/tag_ocelot_8021q.c
+++ b/net/dsa/tag_ocelot_8021q.c
@@ -13,32 +13,6 @@
#include <soc/mscc/ocelot_ptp.h>
#include "dsa_priv.h"
-static struct sk_buff *ocelot_xmit_ptp(struct dsa_port *dp,
- struct sk_buff *skb,
- struct sk_buff *clone)
-{
- struct ocelot *ocelot = dp->ds->priv;
- struct ocelot_port *ocelot_port;
- int port = dp->index;
- u32 rew_op;
-
- if (!ocelot_can_inject(ocelot, 0))
- return NULL;
-
- ocelot_port = ocelot->ports[port];
- rew_op = ocelot_port->ptp_cmd;
-
- /* Retrieve timestamp ID populated inside skb->cb[0] of the
- * clone by ocelot_port_add_txtstamp_skb
- */
- if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
- rew_op |= clone->cb[0] << 3;
-
- ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
-
- return NULL;
-}
-
static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
@@ -46,11 +20,18 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
- struct sk_buff *clone = DSA_SKB_CB(skb)->clone;
+ struct ocelot *ocelot = dp->ds->priv;
+ int port = dp->index;
+ u32 rew_op = 0;
+
+ rew_op = ocelot_ptp_rew_op(skb);
+ if (rew_op) {
+ if (!ocelot_can_inject(ocelot, 0))
+ return NULL;
- /* TX timestamping was requested, so inject through MMIO */
- if (clone)
- return ocelot_xmit_ptp(dp, skb, clone);
+ ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
+ return NULL;
+ }
return dsa_8021q_xmit(skb, netdev, ETH_P_8021Q,
((pcp << VLAN_PRIO_SHIFT) | tx_vid));
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index d6d45d820d79..cf20316094d0 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -713,7 +713,7 @@ static int copy_entries_to_user(unsigned int total_size,
return ret;
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
@@ -800,7 +800,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
return -EFAULT;
name[XT_TABLE_MAXNAMELEN-1] = '\0';
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_lock(NFPROTO_ARP);
#endif
@@ -808,7 +808,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) {
struct arpt_getinfo info;
const struct xt_table_info *private = t->private;
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp;
if (in_compat_syscall()) {
@@ -835,7 +835,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
module_put(t->me);
} else
ret = PTR_ERR(t);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_unlock(NFPROTO_ARP);
#endif
@@ -1044,7 +1044,7 @@ static int do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret;
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_arpt_replace {
char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks;
@@ -1412,7 +1412,7 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
switch (cmd) {
case ARPT_SO_SET_REPLACE:
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len);
else
@@ -1444,7 +1444,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
break;
case ARPT_SO_GET_ENTRIES:
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len);
else
@@ -1499,10 +1499,11 @@ static void __arpt_unregister_table(struct net *net, struct xt_table *table)
int arpt_register_table(struct net *net,
const struct xt_table *table,
const struct arpt_replace *repl,
- const struct nf_hook_ops *ops,
- struct xt_table **res)
+ const struct nf_hook_ops *template_ops)
{
- int ret;
+ struct nf_hook_ops *ops;
+ unsigned int num_ops;
+ int ret, i;
struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0};
void *loc_cpu_entry;
@@ -1516,41 +1517,61 @@ int arpt_register_table(struct net *net,
memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl);
- if (ret != 0)
- goto out_free;
+ if (ret != 0) {
+ xt_free_table_info(newinfo);
+ return ret;
+ }
new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
- ret = PTR_ERR(new_table);
- goto out_free;
+ xt_free_table_info(newinfo);
+ return PTR_ERR(new_table);
}
- /* set res now, will see skbs right after nf_register_net_hooks */
- WRITE_ONCE(*res, new_table);
+ num_ops = hweight32(table->valid_hooks);
+ if (num_ops == 0) {
+ ret = -EINVAL;
+ goto out_free;
+ }
- ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
- if (ret != 0) {
- __arpt_unregister_table(net, new_table);
- *res = NULL;
+ ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
+ if (!ops) {
+ ret = -ENOMEM;
+ goto out_free;
}
+ for (i = 0; i < num_ops; i++)
+ ops[i].priv = new_table;
+
+ new_table->ops = ops;
+
+ ret = nf_register_net_hooks(net, ops, num_ops);
+ if (ret != 0)
+ goto out_free;
+
return ret;
out_free:
- xt_free_table_info(newinfo);
+ __arpt_unregister_table(net, new_table);
return ret;
}
-void arpt_unregister_table_pre_exit(struct net *net, struct xt_table *table,
+void arpt_unregister_table_pre_exit(struct net *net, const char *name,
const struct nf_hook_ops *ops)
{
- nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
+ struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name);
+
+ if (table)
+ nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
}
EXPORT_SYMBOL(arpt_unregister_table_pre_exit);
-void arpt_unregister_table(struct net *net, struct xt_table *table)
+void arpt_unregister_table(struct net *net, const char *name)
{
- __arpt_unregister_table(net, table);
+ struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name);
+
+ if (table)
+ __arpt_unregister_table(net, table);
}
/* The built-in targets: standard (NULL) and error. */
@@ -1559,7 +1580,7 @@ static struct xt_target arpt_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NFPROTO_ARP,
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_user,
.compat_to_user = compat_standard_to_user,
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index 6c300ba5634e..b8f45e9bbec8 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -34,7 +34,7 @@ static unsigned int
arptable_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
- return arpt_do_table(skb, state, state->net->ipv4.arptable_filter);
+ return arpt_do_table(skb, state, priv);
}
static struct nf_hook_ops *arpfilter_ops __read_mostly;
@@ -44,31 +44,22 @@ static int __net_init arptable_filter_table_init(struct net *net)
struct arpt_replace *repl;
int err;
- if (net->ipv4.arptable_filter)
- return 0;
-
repl = arpt_alloc_initial_table(&packet_filter);
if (repl == NULL)
return -ENOMEM;
- err = arpt_register_table(net, &packet_filter, repl, arpfilter_ops,
- &net->ipv4.arptable_filter);
+ err = arpt_register_table(net, &packet_filter, repl, arpfilter_ops);
kfree(repl);
return err;
}
static void __net_exit arptable_filter_net_pre_exit(struct net *net)
{
- if (net->ipv4.arptable_filter)
- arpt_unregister_table_pre_exit(net, net->ipv4.arptable_filter,
- arpfilter_ops);
+ arpt_unregister_table_pre_exit(net, "filter", arpfilter_ops);
}
static void __net_exit arptable_filter_net_exit(struct net *net)
{
- if (!net->ipv4.arptable_filter)
- return;
- arpt_unregister_table(net, net->ipv4.arptable_filter);
- net->ipv4.arptable_filter = NULL;
+ arpt_unregister_table(net, "filter");
}
static struct pernet_operations arptable_filter_net_ops = {
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index f77ea0dbe656..13acb687c19a 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -868,7 +868,7 @@ copy_entries_to_user(unsigned int total_size,
return ret;
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
@@ -957,7 +957,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
return -EFAULT;
name[XT_TABLE_MAXNAMELEN-1] = '\0';
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_lock(AF_INET);
#endif
@@ -965,7 +965,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) {
struct ipt_getinfo info;
const struct xt_table_info *private = t->private;
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp;
if (in_compat_syscall()) {
@@ -993,7 +993,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
module_put(t->me);
} else
ret = PTR_ERR(t);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_unlock(AF_INET);
#endif
@@ -1199,7 +1199,7 @@ do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret;
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ipt_replace {
char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks;
@@ -1621,7 +1621,7 @@ do_ipt_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len)
switch (cmd) {
case IPT_SO_SET_REPLACE:
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len);
else
@@ -1654,7 +1654,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break;
case IPT_SO_GET_ENTRIES:
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len);
else
@@ -1716,9 +1716,11 @@ static void __ipt_unregister_table(struct net *net, struct xt_table *table)
int ipt_register_table(struct net *net, const struct xt_table *table,
const struct ipt_replace *repl,
- const struct nf_hook_ops *ops, struct xt_table **res)
+ const struct nf_hook_ops *template_ops)
{
- int ret;
+ struct nf_hook_ops *ops;
+ unsigned int num_ops;
+ int ret, i;
struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0};
void *loc_cpu_entry;
@@ -1732,50 +1734,65 @@ int ipt_register_table(struct net *net, const struct xt_table *table,
memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl);
- if (ret != 0)
- goto out_free;
+ if (ret != 0) {
+ xt_free_table_info(newinfo);
+ return ret;
+ }
new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
- ret = PTR_ERR(new_table);
- goto out_free;
+ xt_free_table_info(newinfo);
+ return PTR_ERR(new_table);
}
- /* set res now, will see skbs right after nf_register_net_hooks */
- WRITE_ONCE(*res, new_table);
- if (!ops)
+ /* No template? No need to do anything. This is used by 'nat' table, it registers
+ * with the nat core instead of the netfilter core.
+ */
+ if (!template_ops)
return 0;
- ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
- if (ret != 0) {
- __ipt_unregister_table(net, new_table);
- *res = NULL;
+ num_ops = hweight32(table->valid_hooks);
+ if (num_ops == 0) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
+ if (!ops) {
+ ret = -ENOMEM;
+ goto out_free;
}
+ for (i = 0; i < num_ops; i++)
+ ops[i].priv = new_table;
+
+ new_table->ops = ops;
+
+ ret = nf_register_net_hooks(net, ops, num_ops);
+ if (ret != 0)
+ goto out_free;
+
return ret;
out_free:
- xt_free_table_info(newinfo);
+ __ipt_unregister_table(net, new_table);
return ret;
}
-void ipt_unregister_table_pre_exit(struct net *net, struct xt_table *table,
- const struct nf_hook_ops *ops)
+void ipt_unregister_table_pre_exit(struct net *net, const char *name)
{
- nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
-}
+ struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name);
-void ipt_unregister_table_exit(struct net *net, struct xt_table *table)
-{
- __ipt_unregister_table(net, table);
+ if (table)
+ nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
}
-void ipt_unregister_table(struct net *net, struct xt_table *table,
- const struct nf_hook_ops *ops)
+void ipt_unregister_table_exit(struct net *net, const char *name)
{
- if (ops)
- ipt_unregister_table_pre_exit(net, table, ops);
- __ipt_unregister_table(net, table);
+ struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name);
+
+ if (table)
+ __ipt_unregister_table(net, table);
}
/* Returns 1 if the type and code is matched by the range, 0 otherwise */
@@ -1829,7 +1846,7 @@ static struct xt_target ipt_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NFPROTO_IPV4,
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_user,
.compat_to_user = compat_standard_to_user,
@@ -1924,7 +1941,6 @@ static void __exit ip_tables_fini(void)
}
EXPORT_SYMBOL(ipt_register_table);
-EXPORT_SYMBOL(ipt_unregister_table);
EXPORT_SYMBOL(ipt_unregister_table_pre_exit);
EXPORT_SYMBOL(ipt_unregister_table_exit);
EXPORT_SYMBOL(ipt_do_table);
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index a8b980ad11d4..8f7ca67475b7 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -541,7 +541,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
nf_ct_netns_put(par->net, par->family);
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ipt_clusterip_tgt_info
{
u_int32_t flags;
@@ -553,7 +553,7 @@ struct compat_ipt_clusterip_tgt_info
u_int32_t hash_initval;
compat_uptr_t config;
};
-#endif /* CONFIG_COMPAT */
+#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
static struct xt_target clusterip_tg_reg __read_mostly = {
.name = "CLUSTERIP",
@@ -563,9 +563,9 @@ static struct xt_target clusterip_tg_reg __read_mostly = {
.destroy = clusterip_tg_destroy,
.targetsize = sizeof(struct ipt_clusterip_tgt_info),
.usersize = offsetof(struct ipt_clusterip_tgt_info, config),
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ipt_clusterip_tgt_info),
-#endif /* CONFIG_COMPAT */
+#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
.me = THIS_MODULE
};
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 8f7bc1ee7453..8272df7c6ad5 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -34,7 +34,7 @@ static unsigned int
iptable_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
- return ipt_do_table(skb, state, state->net->ipv4.iptable_filter);
+ return ipt_do_table(skb, state, priv);
}
static struct nf_hook_ops *filter_ops __read_mostly;
@@ -48,9 +48,6 @@ static int __net_init iptable_filter_table_init(struct net *net)
struct ipt_replace *repl;
int err;
- if (net->ipv4.iptable_filter)
- return 0;
-
repl = ipt_alloc_initial_table(&packet_filter);
if (repl == NULL)
return -ENOMEM;
@@ -58,8 +55,7 @@ static int __net_init iptable_filter_table_init(struct net *net)
((struct ipt_standard *)repl->entries)[1].target.verdict =
forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
- err = ipt_register_table(net, &packet_filter, repl, filter_ops,
- &net->ipv4.iptable_filter);
+ err = ipt_register_table(net, &packet_filter, repl, filter_ops);
kfree(repl);
return err;
}
@@ -74,17 +70,12 @@ static int __net_init iptable_filter_net_init(struct net *net)
static void __net_exit iptable_filter_net_pre_exit(struct net *net)
{
- if (net->ipv4.iptable_filter)
- ipt_unregister_table_pre_exit(net, net->ipv4.iptable_filter,
- filter_ops);
+ ipt_unregister_table_pre_exit(net, "filter");
}
static void __net_exit iptable_filter_net_exit(struct net *net)
{
- if (!net->ipv4.iptable_filter)
- return;
- ipt_unregister_table_exit(net, net->ipv4.iptable_filter);
- net->ipv4.iptable_filter = NULL;
+ ipt_unregister_table_exit(net, "filter");
}
static struct pernet_operations iptable_filter_net_ops = {
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 833079589273..2abc3836f391 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -37,7 +37,7 @@ static const struct xt_table packet_mangler = {
};
static unsigned int
-ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
+ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state, void *priv)
{
unsigned int ret;
const struct iphdr *iph;
@@ -53,7 +53,7 @@ ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
daddr = iph->daddr;
tos = iph->tos;
- ret = ipt_do_table(skb, state, state->net->ipv4.iptable_mangle);
+ ret = ipt_do_table(skb, state, priv);
/* Reroute for ANY change. */
if (ret != NF_DROP && ret != NF_STOLEN) {
iph = ip_hdr(skb);
@@ -78,8 +78,8 @@ iptable_mangle_hook(void *priv,
const struct nf_hook_state *state)
{
if (state->hook == NF_INET_LOCAL_OUT)
- return ipt_mangle_out(skb, state);
- return ipt_do_table(skb, state, state->net->ipv4.iptable_mangle);
+ return ipt_mangle_out(skb, state, priv);
+ return ipt_do_table(skb, state, priv);
}
static struct nf_hook_ops *mangle_ops __read_mostly;
@@ -88,31 +88,22 @@ static int __net_init iptable_mangle_table_init(struct net *net)
struct ipt_replace *repl;
int ret;
- if (net->ipv4.iptable_mangle)
- return 0;
-
repl = ipt_alloc_initial_table(&packet_mangler);
if (repl == NULL)
return -ENOMEM;
- ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops,
- &net->ipv4.iptable_mangle);
+ ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops);
kfree(repl);
return ret;
}
static void __net_exit iptable_mangle_net_pre_exit(struct net *net)
{
- if (net->ipv4.iptable_mangle)
- ipt_unregister_table_pre_exit(net, net->ipv4.iptable_mangle,
- mangle_ops);
+ ipt_unregister_table_pre_exit(net, "mangle");
}
static void __net_exit iptable_mangle_net_exit(struct net *net)
{
- if (!net->ipv4.iptable_mangle)
- return;
- ipt_unregister_table_exit(net, net->ipv4.iptable_mangle);
- net->ipv4.iptable_mangle = NULL;
+ ipt_unregister_table_exit(net, "mangle");
}
static struct pernet_operations iptable_mangle_net_ops = {
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index b0143b109f25..a9913842ef18 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -13,8 +13,14 @@
#include <net/netfilter/nf_nat.h>
+struct iptable_nat_pernet {
+ struct nf_hook_ops *nf_nat_ops;
+};
+
static int __net_init iptable_nat_table_init(struct net *net);
+static unsigned int iptable_nat_net_id __read_mostly;
+
static const struct xt_table nf_nat_ipv4_table = {
.name = "nat",
.valid_hooks = (1 << NF_INET_PRE_ROUTING) |
@@ -30,7 +36,7 @@ static unsigned int iptable_nat_do_chain(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
- return ipt_do_table(skb, state, state->net->ipv4.nat_table);
+ return ipt_do_table(skb, state, priv);
}
static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
@@ -62,27 +68,49 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
static int ipt_nat_register_lookups(struct net *net)
{
+ struct iptable_nat_pernet *xt_nat_net;
+ struct nf_hook_ops *ops;
+ struct xt_table *table;
int i, ret;
+ xt_nat_net = net_generic(net, iptable_nat_net_id);
+ table = xt_find_table(net, NFPROTO_IPV4, "nat");
+ if (WARN_ON_ONCE(!table))
+ return -ENOENT;
+
+ ops = kmemdup(nf_nat_ipv4_ops, sizeof(nf_nat_ipv4_ops), GFP_KERNEL);
+ if (!ops)
+ return -ENOMEM;
+
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) {
- ret = nf_nat_ipv4_register_fn(net, &nf_nat_ipv4_ops[i]);
+ ops[i].priv = table;
+ ret = nf_nat_ipv4_register_fn(net, &ops[i]);
if (ret) {
while (i)
- nf_nat_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[--i]);
+ nf_nat_ipv4_unregister_fn(net, &ops[--i]);
+ kfree(ops);
return ret;
}
}
+ xt_nat_net->nf_nat_ops = ops;
return 0;
}
static void ipt_nat_unregister_lookups(struct net *net)
{
+ struct iptable_nat_pernet *xt_nat_net = net_generic(net, iptable_nat_net_id);
+ struct nf_hook_ops *ops = xt_nat_net->nf_nat_ops;
int i;
+ if (!ops)
+ return;
+
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++)
- nf_nat_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[i]);
+ nf_nat_ipv4_unregister_fn(net, &ops[i]);
+
+ kfree(ops);
}
static int __net_init iptable_nat_table_init(struct net *net)
@@ -90,24 +118,19 @@ static int __net_init iptable_nat_table_init(struct net *net)
struct ipt_replace *repl;
int ret;
- if (net->ipv4.nat_table)
- return 0;
-
repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
if (repl == NULL)
return -ENOMEM;
- ret = ipt_register_table(net, &nf_nat_ipv4_table, repl,
- NULL, &net->ipv4.nat_table);
+
+ ret = ipt_register_table(net, &nf_nat_ipv4_table, repl, NULL);
if (ret < 0) {
kfree(repl);
return ret;
}
ret = ipt_nat_register_lookups(net);
- if (ret < 0) {
- ipt_unregister_table(net, net->ipv4.nat_table, NULL);
- net->ipv4.nat_table = NULL;
- }
+ if (ret < 0)
+ ipt_unregister_table_exit(net, "nat");
kfree(repl);
return ret;
@@ -115,21 +138,19 @@ static int __net_init iptable_nat_table_init(struct net *net)
static void __net_exit iptable_nat_net_pre_exit(struct net *net)
{
- if (net->ipv4.nat_table)
- ipt_nat_unregister_lookups(net);
+ ipt_nat_unregister_lookups(net);
}
static void __net_exit iptable_nat_net_exit(struct net *net)
{
- if (!net->ipv4.nat_table)
- return;
- ipt_unregister_table_exit(net, net->ipv4.nat_table);
- net->ipv4.nat_table = NULL;
+ ipt_unregister_table_exit(net, "nat");
}
static struct pernet_operations iptable_nat_net_ops = {
.pre_exit = iptable_nat_net_pre_exit,
.exit = iptable_nat_net_exit,
+ .id = &iptable_nat_net_id,
+ .size = sizeof(struct iptable_nat_pernet),
};
static int __init iptable_nat_init(void)
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 9abfe6bf2cb9..ceef397c1f5f 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -41,7 +41,7 @@ static unsigned int
iptable_raw_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
- return ipt_do_table(skb, state, state->net->ipv4.iptable_raw);
+ return ipt_do_table(skb, state, priv);
}
static struct nf_hook_ops *rawtable_ops __read_mostly;
@@ -55,31 +55,22 @@ static int __net_init iptable_raw_table_init(struct net *net)
if (raw_before_defrag)
table = &packet_raw_before_defrag;
- if (net->ipv4.iptable_raw)
- return 0;
-
repl = ipt_alloc_initial_table(table);
if (repl == NULL)
return -ENOMEM;
- ret = ipt_register_table(net, table, repl, rawtable_ops,
- &net->ipv4.iptable_raw);
+ ret = ipt_register_table(net, table, repl, rawtable_ops);
kfree(repl);
return ret;
}
static void __net_exit iptable_raw_net_pre_exit(struct net *net)
{
- if (net->ipv4.iptable_raw)
- ipt_unregister_table_pre_exit(net, net->ipv4.iptable_raw,
- rawtable_ops);
+ ipt_unregister_table_pre_exit(net, "raw");
}
static void __net_exit iptable_raw_net_exit(struct net *net)
{
- if (!net->ipv4.iptable_raw)
- return;
- ipt_unregister_table_exit(net, net->ipv4.iptable_raw);
- net->ipv4.iptable_raw = NULL;
+ ipt_unregister_table_exit(net, "raw");
}
static struct pernet_operations iptable_raw_net_ops = {
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
index 415c1975d770..77973f5fd8f6 100644
--- a/net/ipv4/netfilter/iptable_security.c
+++ b/net/ipv4/netfilter/iptable_security.c
@@ -40,7 +40,7 @@ static unsigned int
iptable_security_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
- return ipt_do_table(skb, state, state->net->ipv4.iptable_security);
+ return ipt_do_table(skb, state, priv);
}
static struct nf_hook_ops *sectbl_ops __read_mostly;
@@ -50,31 +50,22 @@ static int __net_init iptable_security_table_init(struct net *net)
struct ipt_replace *repl;
int ret;
- if (net->ipv4.iptable_security)
- return 0;
-
repl = ipt_alloc_initial_table(&security_table);
if (repl == NULL)
return -ENOMEM;
- ret = ipt_register_table(net, &security_table, repl, sectbl_ops,
- &net->ipv4.iptable_security);
+ ret = ipt_register_table(net, &security_table, repl, sectbl_ops);
kfree(repl);
return ret;
}
static void __net_exit iptable_security_net_pre_exit(struct net *net)
{
- if (net->ipv4.iptable_security)
- ipt_unregister_table_pre_exit(net, net->ipv4.iptable_security,
- sectbl_ops);
+ ipt_unregister_table_pre_exit(net, "security");
}
static void __net_exit iptable_security_net_exit(struct net *net)
{
- if (!net->ipv4.iptable_security)
- return;
- ipt_unregister_table_exit(net, net->ipv4.iptable_security);
- net->ipv4.iptable_security = NULL;
+ ipt_unregister_table_exit(net, "security");
}
static struct pernet_operations iptable_security_net_ops = {
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index ffdcc2b9360f..613432a36f0a 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -141,14 +141,16 @@ int nf_defrag_ipv4_enable(struct net *net)
struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
int err = 0;
- might_sleep();
-
- if (nf_defrag->users)
- return 0;
-
mutex_lock(&defrag4_mutex);
- if (nf_defrag->users)
+ if (nf_defrag->users == UINT_MAX) {
+ err = -EOVERFLOW;
goto out_unlock;
+ }
+
+ if (nf_defrag->users) {
+ nf_defrag->users++;
+ goto out_unlock;
+ }
err = nf_register_net_hooks(net, ipv4_defrag_ops,
ARRAY_SIZE(ipv4_defrag_ops));
@@ -161,6 +163,22 @@ int nf_defrag_ipv4_enable(struct net *net)
}
EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable);
+void nf_defrag_ipv4_disable(struct net *net)
+{
+ struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
+
+ mutex_lock(&defrag4_mutex);
+ if (nf_defrag->users) {
+ nf_defrag->users--;
+ if (nf_defrag->users == 0)
+ nf_unregister_net_hooks(net, ipv4_defrag_ops,
+ ARRAY_SIZE(ipv4_defrag_ops));
+ }
+
+ mutex_unlock(&defrag4_mutex);
+}
+EXPORT_SYMBOL_GPL(nf_defrag_ipv4_disable);
+
module_init(nf_defrag_init);
module_exit(nf_defrag_fini);
diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c
index d3d6b6a66e5f..04d5fcdfa6e0 100644
--- a/net/ipv6/mcast_snoop.c
+++ b/net/ipv6/mcast_snoop.c
@@ -109,7 +109,7 @@ static int ipv6_mc_check_mld_msg(struct sk_buff *skb)
struct mld_msg *mld;
if (!ipv6_mc_may_pull(skb, len))
- return -EINVAL;
+ return -ENODATA;
mld = (struct mld_msg *)skb_transport_header(skb);
@@ -122,7 +122,7 @@ static int ipv6_mc_check_mld_msg(struct sk_buff *skb)
case ICMPV6_MGM_QUERY:
return ipv6_mc_check_mld_query(skb);
default:
- return -ENOMSG;
+ return -ENODATA;
}
}
@@ -131,7 +131,7 @@ static inline __sum16 ipv6_mc_validate_checksum(struct sk_buff *skb)
return skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo);
}
-int ipv6_mc_check_icmpv6(struct sk_buff *skb)
+static int ipv6_mc_check_icmpv6(struct sk_buff *skb)
{
unsigned int len = skb_transport_offset(skb) + sizeof(struct icmp6hdr);
unsigned int transport_len = ipv6_transport_len(skb);
@@ -150,7 +150,6 @@ int ipv6_mc_check_icmpv6(struct sk_buff *skb)
return 0;
}
-EXPORT_SYMBOL(ipv6_mc_check_icmpv6);
/**
* ipv6_mc_check_mld - checks whether this is a sane MLD packet
@@ -161,7 +160,10 @@ EXPORT_SYMBOL(ipv6_mc_check_icmpv6);
*
* -EINVAL: A broken packet was detected, i.e. it violates some internet
* standard
- * -ENOMSG: IP header validation succeeded but it is not an MLD packet.
+ * -ENOMSG: IP header validation succeeded but it is not an ICMPv6 packet
+ * with a hop-by-hop option.
+ * -ENODATA: IP+ICMPv6 header with hop-by-hop option validation succeeded
+ * but it is not an MLD packet.
* -ENOMEM: A memory allocation failure happened.
*
* Caller needs to set the skb network header and free any returned skb if it
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index eb2b5404806c..e810a23baf99 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -884,7 +884,7 @@ copy_entries_to_user(unsigned int total_size,
return ret;
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
@@ -973,7 +973,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
return -EFAULT;
name[XT_TABLE_MAXNAMELEN-1] = '\0';
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_lock(AF_INET6);
#endif
@@ -981,7 +981,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) {
struct ip6t_getinfo info;
const struct xt_table_info *private = t->private;
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp;
if (in_compat_syscall()) {
@@ -1009,7 +1009,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
module_put(t->me);
} else
ret = PTR_ERR(t);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
xt_compat_unlock(AF_INET6);
#endif
@@ -1215,7 +1215,7 @@ do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret;
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ip6t_replace {
char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks;
@@ -1630,7 +1630,7 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len)
switch (cmd) {
case IP6T_SO_SET_REPLACE:
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len);
else
@@ -1663,7 +1663,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break;
case IP6T_SO_GET_ENTRIES:
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len);
else
@@ -1725,10 +1725,11 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table)
int ip6t_register_table(struct net *net, const struct xt_table *table,
const struct ip6t_replace *repl,
- const struct nf_hook_ops *ops,
- struct xt_table **res)
+ const struct nf_hook_ops *template_ops)
{
- int ret;
+ struct nf_hook_ops *ops;
+ unsigned int num_ops;
+ int ret, i;
struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0};
void *loc_cpu_entry;
@@ -1742,50 +1743,62 @@ int ip6t_register_table(struct net *net, const struct xt_table *table,
memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl);
- if (ret != 0)
- goto out_free;
+ if (ret != 0) {
+ xt_free_table_info(newinfo);
+ return ret;
+ }
new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) {
- ret = PTR_ERR(new_table);
- goto out_free;
+ xt_free_table_info(newinfo);
+ return PTR_ERR(new_table);
}
- /* set res now, will see skbs right after nf_register_net_hooks */
- WRITE_ONCE(*res, new_table);
- if (!ops)
+ if (!template_ops)
return 0;
- ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
- if (ret != 0) {
- __ip6t_unregister_table(net, new_table);
- *res = NULL;
+ num_ops = hweight32(table->valid_hooks);
+ if (num_ops == 0) {
+ ret = -EINVAL;
+ goto out_free;
}
+ ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
+ if (!ops) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ for (i = 0; i < num_ops; i++)
+ ops[i].priv = new_table;
+
+ new_table->ops = ops;
+
+ ret = nf_register_net_hooks(net, ops, num_ops);
+ if (ret != 0)
+ goto out_free;
+
return ret;
out_free:
- xt_free_table_info(newinfo);
+ __ip6t_unregister_table(net, new_table);
return ret;
}
-void ip6t_unregister_table_pre_exit(struct net *net, struct xt_table *table,
- const struct nf_hook_ops *ops)
+void ip6t_unregister_table_pre_exit(struct net *net, const char *name)
{
- nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
-}
+ struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name);
-void ip6t_unregister_table_exit(struct net *net, struct xt_table *table)
-{
- __ip6t_unregister_table(net, table);
+ if (table)
+ nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
}
-void ip6t_unregister_table(struct net *net, struct xt_table *table,
- const struct nf_hook_ops *ops)
+void ip6t_unregister_table_exit(struct net *net, const char *name)
{
- if (ops)
- ip6t_unregister_table_pre_exit(net, table, ops);
- __ip6t_unregister_table(net, table);
+ struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name);
+
+ if (table)
+ __ip6t_unregister_table(net, table);
}
/* Returns 1 if the type and code is matched by the range, 0 otherwise */
@@ -1840,7 +1853,7 @@ static struct xt_target ip6t_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NFPROTO_IPV6,
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_user,
.compat_to_user = compat_standard_to_user,
@@ -1935,7 +1948,6 @@ static void __exit ip6_tables_fini(void)
}
EXPORT_SYMBOL(ip6t_register_table);
-EXPORT_SYMBOL(ip6t_unregister_table);
EXPORT_SYMBOL(ip6t_unregister_table_pre_exit);
EXPORT_SYMBOL(ip6t_unregister_table_exit);
EXPORT_SYMBOL(ip6t_do_table);
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index 88337b51ffbf..bb784ea7bbd3 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -35,7 +35,7 @@ static unsigned int
ip6table_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
- return ip6t_do_table(skb, state, state->net->ipv6.ip6table_filter);
+ return ip6t_do_table(skb, state, priv);
}
static struct nf_hook_ops *filter_ops __read_mostly;
@@ -49,9 +49,6 @@ static int __net_init ip6table_filter_table_init(struct net *net)
struct ip6t_replace *repl;
int err;
- if (net->ipv6.ip6table_filter)
- return 0;
-
repl = ip6t_alloc_initial_table(&packet_filter);
if (repl == NULL)
return -ENOMEM;
@@ -59,8 +56,7 @@ static int __net_init ip6table_filter_table_init(struct net *net)
((struct ip6t_standard *)repl->entries)[1].target.verdict =
forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
- err = ip6t_register_table(net, &packet_filter, repl, filter_ops,
- &net->ipv6.ip6table_filter);
+ err = ip6t_register_table(net, &packet_filter, repl, filter_ops);
kfree(repl);
return err;
}
@@ -75,17 +71,12 @@ static int __net_init ip6table_filter_net_init(struct net *net)
static void __net_exit ip6table_filter_net_pre_exit(struct net *net)
{
- if (net->ipv6.ip6table_filter)
- ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_filter,
- filter_ops);
+ ip6t_unregister_table_pre_exit(net, "filter");
}
static void __net_exit ip6table_filter_net_exit(struct net *net)
{
- if (!net->ipv6.ip6table_filter)
- return;
- ip6t_unregister_table_exit(net, net->ipv6.ip6table_filter);
- net->ipv6.ip6table_filter = NULL;
+ ip6t_unregister_table_exit(net, "filter");
}
static struct pernet_operations ip6table_filter_net_ops = {
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index cee74803d7a1..c76cffd63041 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -32,7 +32,7 @@ static const struct xt_table packet_mangler = {
};
static unsigned int
-ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
+ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state, void *priv)
{
unsigned int ret;
struct in6_addr saddr, daddr;
@@ -49,7 +49,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
/* flowlabel and prio (includes version, which shouldn't change either */
flowlabel = *((u_int32_t *)ipv6_hdr(skb));
- ret = ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle);
+ ret = ip6t_do_table(skb, state, priv);
if (ret != NF_DROP && ret != NF_STOLEN &&
(!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) ||
@@ -71,8 +71,8 @@ ip6table_mangle_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
if (state->hook == NF_INET_LOCAL_OUT)
- return ip6t_mangle_out(skb, state);
- return ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle);
+ return ip6t_mangle_out(skb, state, priv);
+ return ip6t_do_table(skb, state, priv);
}
static struct nf_hook_ops *mangle_ops __read_mostly;
@@ -81,32 +81,22 @@ static int __net_init ip6table_mangle_table_init(struct net *net)
struct ip6t_replace *repl;
int ret;
- if (net->ipv6.ip6table_mangle)
- return 0;
-
repl = ip6t_alloc_initial_table(&packet_mangler);
if (repl == NULL)
return -ENOMEM;
- ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops,
- &net->ipv6.ip6table_mangle);
+ ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops);
kfree(repl);
return ret;
}
static void __net_exit ip6table_mangle_net_pre_exit(struct net *net)
{
- if (net->ipv6.ip6table_mangle)
- ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_mangle,
- mangle_ops);
+ ip6t_unregister_table_pre_exit(net, "mangle");
}
static void __net_exit ip6table_mangle_net_exit(struct net *net)
{
- if (!net->ipv6.ip6table_mangle)
- return;
-
- ip6t_unregister_table_exit(net, net->ipv6.ip6table_mangle);
- net->ipv6.ip6table_mangle = NULL;
+ ip6t_unregister_table_exit(net, "mangle");
}
static struct pernet_operations ip6table_mangle_net_ops = {
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index 0a23265e3caa..b0292251e655 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -15,8 +15,14 @@
#include <net/netfilter/nf_nat.h>
+struct ip6table_nat_pernet {
+ struct nf_hook_ops *nf_nat_ops;
+};
+
static int __net_init ip6table_nat_table_init(struct net *net);
+static unsigned int ip6table_nat_net_id __read_mostly;
+
static const struct xt_table nf_nat_ipv6_table = {
.name = "nat",
.valid_hooks = (1 << NF_INET_PRE_ROUTING) |
@@ -32,7 +38,7 @@ static unsigned int ip6table_nat_do_chain(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
- return ip6t_do_table(skb, state, state->net->ipv6.ip6table_nat);
+ return ip6t_do_table(skb, state, priv);
}
static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
@@ -64,27 +70,49 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
static int ip6t_nat_register_lookups(struct net *net)
{
+ struct ip6table_nat_pernet *xt_nat_net;
+ struct nf_hook_ops *ops;
+ struct xt_table *table;
int i, ret;
+ table = xt_find_table(net, NFPROTO_IPV6, "nat");
+ if (WARN_ON_ONCE(!table))
+ return -ENOENT;
+
+ xt_nat_net = net_generic(net, ip6table_nat_net_id);
+ ops = kmemdup(nf_nat_ipv6_ops, sizeof(nf_nat_ipv6_ops), GFP_KERNEL);
+ if (!ops)
+ return -ENOMEM;
+
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) {
- ret = nf_nat_ipv6_register_fn(net, &nf_nat_ipv6_ops[i]);
+ ops[i].priv = table;
+ ret = nf_nat_ipv6_register_fn(net, &ops[i]);
if (ret) {
while (i)
- nf_nat_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[--i]);
+ nf_nat_ipv6_unregister_fn(net, &ops[--i]);
+ kfree(ops);
return ret;
}
}
+ xt_nat_net->nf_nat_ops = ops;
return 0;
}
static void ip6t_nat_unregister_lookups(struct net *net)
{
+ struct ip6table_nat_pernet *xt_nat_net = net_generic(net, ip6table_nat_net_id);
+ struct nf_hook_ops *ops = xt_nat_net->nf_nat_ops;
int i;
+ if (!ops)
+ return;
+
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++)
- nf_nat_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[i]);
+ nf_nat_ipv6_unregister_fn(net, &ops[i]);
+
+ kfree(ops);
}
static int __net_init ip6table_nat_table_init(struct net *net)
@@ -92,45 +120,39 @@ static int __net_init ip6table_nat_table_init(struct net *net)
struct ip6t_replace *repl;
int ret;
- if (net->ipv6.ip6table_nat)
- return 0;
-
repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
if (repl == NULL)
return -ENOMEM;
ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl,
- NULL, &net->ipv6.ip6table_nat);
+ NULL);
if (ret < 0) {
kfree(repl);
return ret;
}
ret = ip6t_nat_register_lookups(net);
- if (ret < 0) {
- ip6t_unregister_table(net, net->ipv6.ip6table_nat, NULL);
- net->ipv6.ip6table_nat = NULL;
- }
+ if (ret < 0)
+ ip6t_unregister_table_exit(net, "nat");
+
kfree(repl);
return ret;
}
static void __net_exit ip6table_nat_net_pre_exit(struct net *net)
{
- if (net->ipv6.ip6table_nat)
- ip6t_nat_unregister_lookups(net);
+ ip6t_nat_unregister_lookups(net);
}
static void __net_exit ip6table_nat_net_exit(struct net *net)
{
- if (!net->ipv6.ip6table_nat)
- return;
- ip6t_unregister_table_exit(net, net->ipv6.ip6table_nat);
- net->ipv6.ip6table_nat = NULL;
+ ip6t_unregister_table_exit(net, "nat");
}
static struct pernet_operations ip6table_nat_net_ops = {
.pre_exit = ip6table_nat_net_pre_exit,
.exit = ip6table_nat_net_exit,
+ .id = &ip6table_nat_net_id,
+ .size = sizeof(struct ip6table_nat_pernet),
};
static int __init ip6table_nat_init(void)
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index 8f9e742226f7..f63c106c521e 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -40,7 +40,7 @@ static unsigned int
ip6table_raw_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
- return ip6t_do_table(skb, state, state->net->ipv6.ip6table_raw);
+ return ip6t_do_table(skb, state, priv);
}
static struct nf_hook_ops *rawtable_ops __read_mostly;
@@ -54,31 +54,22 @@ static int __net_init ip6table_raw_table_init(struct net *net)
if (raw_before_defrag)
table = &packet_raw_before_defrag;
- if (net->ipv6.ip6table_raw)
- return 0;
-
repl = ip6t_alloc_initial_table(table);
if (repl == NULL)
return -ENOMEM;
- ret = ip6t_register_table(net, table, repl, rawtable_ops,
- &net->ipv6.ip6table_raw);
+ ret = ip6t_register_table(net, table, repl, rawtable_ops);
kfree(repl);
return ret;
}
static void __net_exit ip6table_raw_net_pre_exit(struct net *net)
{
- if (net->ipv6.ip6table_raw)
- ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_raw,
- rawtable_ops);
+ ip6t_unregister_table_pre_exit(net, "raw");
}
static void __net_exit ip6table_raw_net_exit(struct net *net)
{
- if (!net->ipv6.ip6table_raw)
- return;
- ip6t_unregister_table_exit(net, net->ipv6.ip6table_raw);
- net->ipv6.ip6table_raw = NULL;
+ ip6t_unregister_table_exit(net, "raw");
}
static struct pernet_operations ip6table_raw_net_ops = {
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
index 5e8c48fed032..8dc335cf450b 100644
--- a/net/ipv6/netfilter/ip6table_security.c
+++ b/net/ipv6/netfilter/ip6table_security.c
@@ -39,7 +39,7 @@ static unsigned int
ip6table_security_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
- return ip6t_do_table(skb, state, state->net->ipv6.ip6table_security);
+ return ip6t_do_table(skb, state, priv);
}
static struct nf_hook_ops *sectbl_ops __read_mostly;
@@ -49,31 +49,22 @@ static int __net_init ip6table_security_table_init(struct net *net)
struct ip6t_replace *repl;
int ret;
- if (net->ipv6.ip6table_security)
- return 0;
-
repl = ip6t_alloc_initial_table(&security_table);
if (repl == NULL)
return -ENOMEM;
- ret = ip6t_register_table(net, &security_table, repl, sectbl_ops,
- &net->ipv6.ip6table_security);
+ ret = ip6t_register_table(net, &security_table, repl, sectbl_ops);
kfree(repl);
return ret;
}
static void __net_exit ip6table_security_net_pre_exit(struct net *net)
{
- if (net->ipv6.ip6table_security)
- ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_security,
- sectbl_ops);
+ ip6t_unregister_table_pre_exit(net, "security");
}
static void __net_exit ip6table_security_net_exit(struct net *net)
{
- if (!net->ipv6.ip6table_security)
- return;
- ip6t_unregister_table_exit(net, net->ipv6.ip6table_security);
- net->ipv6.ip6table_security = NULL;
+ ip6t_unregister_table_exit(net, "security");
}
static struct pernet_operations ip6table_security_net_ops = {
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
index 402dc4ca9504..e8a59d8bf2ad 100644
--- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
+++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
@@ -137,14 +137,16 @@ int nf_defrag_ipv6_enable(struct net *net)
struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
int err = 0;
- might_sleep();
-
- if (nf_frag->users)
- return 0;
-
mutex_lock(&defrag6_mutex);
- if (nf_frag->users)
+ if (nf_frag->users == UINT_MAX) {
+ err = -EOVERFLOW;
+ goto out_unlock;
+ }
+
+ if (nf_frag->users) {
+ nf_frag->users++;
goto out_unlock;
+ }
err = nf_register_net_hooks(net, ipv6_defrag_ops,
ARRAY_SIZE(ipv6_defrag_ops));
@@ -157,6 +159,21 @@ int nf_defrag_ipv6_enable(struct net *net)
}
EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable);
+void nf_defrag_ipv6_disable(struct net *net)
+{
+ struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
+
+ mutex_lock(&defrag6_mutex);
+ if (nf_frag->users) {
+ nf_frag->users--;
+ if (nf_frag->users == 0)
+ nf_unregister_net_hooks(net, ipv6_defrag_ops,
+ ARRAY_SIZE(ipv6_defrag_ops));
+ }
+ mutex_unlock(&defrag6_mutex);
+}
+EXPORT_SYMBOL_GPL(nf_defrag_ipv6_disable);
+
module_init(nf_defrag_init);
module_exit(nf_defrag_fini);
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 2ee20743cb41..53486b162f01 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1478,11 +1478,15 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
tunnel->l2tp_net = net;
pn = l2tp_pernet(net);
+ sk = sock->sk;
+ sock_hold(sk);
+ tunnel->sock = sk;
+
spin_lock_bh(&pn->l2tp_tunnel_list_lock);
list_for_each_entry(tunnel_walk, &pn->l2tp_tunnel_list, list) {
if (tunnel_walk->tunnel_id == tunnel->tunnel_id) {
spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
-
+ sock_put(sk);
ret = -EEXIST;
goto err_sock;
}
@@ -1490,10 +1494,6 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list);
spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
- sk = sock->sk;
- sock_hold(sk);
- tunnel->sock = sk;
-
if (tunnel->encap == L2TP_ENCAPTYPE_UDP) {
struct udp_tunnel_sock_cfg udp_cfg = {
.sk_user_data = tunnel,
diff --git a/net/llc/llc_station.c b/net/llc/llc_station.c
index c29170e767a8..05c6ae092053 100644
--- a/net/llc/llc_station.c
+++ b/net/llc/llc_station.c
@@ -54,7 +54,6 @@ static int llc_station_ac_send_xid_r(struct sk_buff *skb)
if (!nskb)
goto out;
- rc = 0;
llc_pdu_decode_sa(skb, mac_da);
llc_pdu_decode_ssap(skb, &dsap);
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
@@ -83,7 +82,6 @@ static int llc_station_ac_send_test_r(struct sk_buff *skb)
if (!nskb)
goto out;
- rc = 0;
llc_pdu_decode_sa(skb, mac_da);
llc_pdu_decode_ssap(skb, &dsap);
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 47bab701555f..05a21dd072df 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -1019,7 +1019,6 @@ static int mpls_route_add(struct mpls_route_config *cfg,
goto errout;
}
- err = -ENOMEM;
rt = mpls_rt_alloc(nhs, max_via_alen, max_labels);
if (IS_ERR(rt)) {
err = PTR_ERR(rt);
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 8bf21996734d..29a2d690d8d5 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -392,6 +392,14 @@ static bool mptcp_pending_data_fin(struct sock *sk, u64 *seq)
return false;
}
+static void mptcp_set_datafin_timeout(const struct sock *sk)
+{
+ struct inet_connection_sock *icsk = inet_csk(sk);
+
+ mptcp_sk(sk)->timer_ival = min(TCP_RTO_MAX,
+ TCP_RTO_MIN << icsk->icsk_retransmits);
+}
+
static void mptcp_set_timeout(const struct sock *sk, const struct sock *ssk)
{
long tout = ssk && inet_csk(ssk)->icsk_pending ?
@@ -1062,7 +1070,7 @@ out:
}
if (snd_una == READ_ONCE(msk->snd_nxt)) {
- if (msk->timer_ival)
+ if (msk->timer_ival && !mptcp_data_fin_enabled(msk))
mptcp_stop_timer(sk);
} else {
mptcp_reset_timer(sk);
@@ -2287,8 +2295,19 @@ static void __mptcp_retrans(struct sock *sk)
__mptcp_clean_una_wakeup(sk);
dfrag = mptcp_rtx_head(sk);
- if (!dfrag)
+ if (!dfrag) {
+ if (mptcp_data_fin_enabled(msk)) {
+ struct inet_connection_sock *icsk = inet_csk(sk);
+
+ icsk->icsk_retransmits++;
+ mptcp_set_datafin_timeout(sk);
+ mptcp_send_ack(msk);
+
+ goto reset_timer;
+ }
+
return;
+ }
ssk = mptcp_subflow_get_retrans(msk);
if (!ssk)
@@ -2474,6 +2493,8 @@ void mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how)
pr_debug("Sending DATA_FIN on subflow %p", ssk);
mptcp_set_timeout(sk, ssk);
tcp_send_ack(ssk);
+ if (!mptcp_timer_pending(sk))
+ mptcp_reset_timer(sk);
}
break;
}
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index fcd8682704c4..56a2531a3402 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -728,6 +728,16 @@ config NETFILTER_XTABLES
if NETFILTER_XTABLES
+config NETFILTER_XTABLES_COMPAT
+ bool "Netfilter Xtables 32bit support"
+ depends on COMPAT
+ default y
+ help
+ This option provides a translation layer to run 32bit arp,ip(6),ebtables
+ binaries on 64bit kernels.
+
+ If unsure, say N.
+
comment "Xtables combined modules"
config NETFILTER_XT_MARK
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index 359ff8ec236a..de2d20c37cda 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -1031,26 +1031,22 @@ find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index,
return 0;
}
-static int ip_set_none(struct net *net, struct sock *ctnl, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_none(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
return -EOPNOTSUPP;
}
-static int ip_set_create(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_create(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(net);
+ struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *set, *clash = NULL;
ip_set_id_t index = IPSET_INVALID_ID;
struct nlattr *tb[IPSET_ATTR_CREATE_MAX + 1] = {};
const char *name, *typename;
u8 family, revision;
- u32 flags = flag_exist(nlh);
+ u32 flags = flag_exist(info->nlh);
int ret = 0;
if (unlikely(protocol_min_failed(attr) ||
@@ -1101,7 +1097,7 @@ static int ip_set_create(struct net *net, struct sock *ctnl,
/* Set create flags depending on the type revision */
set->flags |= set->type->create_flags[revision];
- ret = set->type->create(net, set, tb, flags);
+ ret = set->type->create(info->net, set, tb, flags);
if (ret != 0)
goto put_out;
@@ -1183,12 +1179,10 @@ ip_set_destroy_set(struct ip_set *set)
kfree(set);
}
-static int ip_set_destroy(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(net);
+ struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *s;
ip_set_id_t i;
int ret = 0;
@@ -1230,7 +1224,7 @@ static int ip_set_destroy(struct net *net, struct sock *ctnl,
/* Modified by ip_set_destroy() only, which is serialized */
inst->is_destroyed = false;
} else {
- u32 flags = flag_exist(nlh);
+ u32 flags = flag_exist(info->nlh);
s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
&i);
if (!s) {
@@ -1264,12 +1258,10 @@ ip_set_flush_set(struct ip_set *set)
ip_set_unlock(set);
}
-static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_flush(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(net);
+ struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *s;
ip_set_id_t i;
@@ -1304,12 +1296,10 @@ ip_set_setname2_policy[IPSET_ATTR_CMD_MAX + 1] = {
.len = IPSET_MAXNAMELEN - 1 },
};
-static int ip_set_rename(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_rename(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(net);
+ struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *set, *s;
const char *name2;
ip_set_id_t i;
@@ -1354,12 +1344,10 @@ out:
* so the ip_set_list always contains valid pointers to the sets.
*/
-static int ip_set_swap(struct net *net, struct sock *ctnl, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_swap(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(net);
+ struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *from, *to;
ip_set_id_t from_id, to_id;
char from_name[IPSET_MAXNAMELEN];
@@ -1669,10 +1657,8 @@ out:
return ret < 0 ? ret : skb->len;
}
-static int ip_set_dump(struct net *net, struct sock *ctnl, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_dump(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
if (unlikely(protocol_min_failed(attr)))
return -IPSET_ERR_PROTOCOL;
@@ -1683,7 +1669,7 @@ static int ip_set_dump(struct net *net, struct sock *ctnl, struct sk_buff *skb,
.dump = ip_set_dump_do,
.done = ip_set_dump_done,
};
- return netlink_dump_start(ctnl, skb, nlh, &c);
+ return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
}
@@ -1817,30 +1803,24 @@ static int ip_set_ad(struct net *net, struct sock *ctnl,
return ret;
}
-static int ip_set_uadd(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_uadd(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
- return ip_set_ad(net, ctnl, skb,
- IPSET_ADD, nlh, attr, extack);
+ return ip_set_ad(info->net, info->sk, skb,
+ IPSET_ADD, info->nlh, attr, info->extack);
}
-static int ip_set_udel(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_udel(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
- return ip_set_ad(net, ctnl, skb,
- IPSET_DEL, nlh, attr, extack);
+ return ip_set_ad(info->net, info->sk, skb,
+ IPSET_DEL, info->nlh, attr, info->extack);
}
-static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_utest(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(net);
+ struct ip_set_net *inst = ip_set_pernet(info->net);
struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
int ret = 0;
@@ -1872,12 +1852,10 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb,
/* Get headed data of a set */
-static int ip_set_header(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_header(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(net);
+ struct ip_set_net *inst = ip_set_pernet(info->net);
const struct ip_set *set;
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
@@ -1895,7 +1873,7 @@ static int ip_set_header(struct net *net, struct sock *ctnl,
if (!skb2)
return -ENOMEM;
- nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
+ nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, info->nlh->nlmsg_seq, 0,
IPSET_CMD_HEADER);
if (!nlh2)
goto nlmsg_failure;
@@ -1907,7 +1885,8 @@ static int ip_set_header(struct net *net, struct sock *ctnl,
goto nla_put_failure;
nlmsg_end(skb2, nlh2);
- ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
+ ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (ret < 0)
return ret;
@@ -1929,10 +1908,8 @@ static const struct nla_policy ip_set_type_policy[IPSET_ATTR_CMD_MAX + 1] = {
[IPSET_ATTR_FAMILY] = { .type = NLA_U8 },
};
-static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_type(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
@@ -1955,7 +1932,7 @@ static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb,
if (!skb2)
return -ENOMEM;
- nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
+ nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, info->nlh->nlmsg_seq, 0,
IPSET_CMD_TYPE);
if (!nlh2)
goto nlmsg_failure;
@@ -1968,7 +1945,8 @@ static int ip_set_type(struct net *net, struct sock *ctnl, struct sk_buff *skb,
nlmsg_end(skb2, nlh2);
pr_debug("Send TYPE, nlmsg_len: %u\n", nlh2->nlmsg_len);
- ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
+ ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (ret < 0)
return ret;
@@ -1988,10 +1966,8 @@ ip_set_protocol_policy[IPSET_ATTR_CMD_MAX + 1] = {
[IPSET_ATTR_PROTOCOL] = { .type = NLA_U8 },
};
-static int ip_set_protocol(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_protocol(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
@@ -2004,7 +1980,7 @@ static int ip_set_protocol(struct net *net, struct sock *ctnl,
if (!skb2)
return -ENOMEM;
- nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
+ nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, info->nlh->nlmsg_seq, 0,
IPSET_CMD_PROTOCOL);
if (!nlh2)
goto nlmsg_failure;
@@ -2014,7 +1990,8 @@ static int ip_set_protocol(struct net *net, struct sock *ctnl,
goto nla_put_failure;
nlmsg_end(skb2, nlh2);
- ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
+ ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (ret < 0)
return ret;
@@ -2029,12 +2006,10 @@ nlmsg_failure:
/* Get set by name or index, from userspace */
-static int ip_set_byname(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_byname(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(net);
+ struct ip_set_net *inst = ip_set_pernet(info->net);
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
ip_set_id_t id = IPSET_INVALID_ID;
@@ -2053,7 +2028,7 @@ static int ip_set_byname(struct net *net, struct sock *ctnl,
if (!skb2)
return -ENOMEM;
- nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
+ nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, info->nlh->nlmsg_seq, 0,
IPSET_CMD_GET_BYNAME);
if (!nlh2)
goto nlmsg_failure;
@@ -2063,7 +2038,8 @@ static int ip_set_byname(struct net *net, struct sock *ctnl,
goto nla_put_failure;
nlmsg_end(skb2, nlh2);
- ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
+ ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (ret < 0)
return ret;
@@ -2081,12 +2057,10 @@ static const struct nla_policy ip_set_index_policy[IPSET_ATTR_CMD_MAX + 1] = {
[IPSET_ATTR_INDEX] = { .type = NLA_U16 },
};
-static int ip_set_byindex(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const attr[],
- struct netlink_ext_ack *extack)
+static int ip_set_byindex(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(net);
+ struct ip_set_net *inst = ip_set_pernet(info->net);
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
ip_set_id_t id = IPSET_INVALID_ID;
@@ -2108,7 +2082,7 @@ static int ip_set_byindex(struct net *net, struct sock *ctnl,
if (!skb2)
return -ENOMEM;
- nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
+ nlh2 = start_msg(skb2, NETLINK_CB(skb).portid, info->nlh->nlmsg_seq, 0,
IPSET_CMD_GET_BYINDEX);
if (!nlh2)
goto nlmsg_failure;
@@ -2117,7 +2091,8 @@ static int ip_set_byindex(struct net *net, struct sock *ctnl,
goto nla_put_failure;
nlmsg_end(skb2, nlh2);
- ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
+ ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (ret < 0)
return ret;
@@ -2133,80 +2108,96 @@ nlmsg_failure:
static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
[IPSET_CMD_NONE] = {
.call = ip_set_none,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
},
[IPSET_CMD_CREATE] = {
.call = ip_set_create,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_create_policy,
},
[IPSET_CMD_DESTROY] = {
.call = ip_set_destroy,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy,
},
[IPSET_CMD_FLUSH] = {
.call = ip_set_flush,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy,
},
[IPSET_CMD_RENAME] = {
.call = ip_set_rename,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname2_policy,
},
[IPSET_CMD_SWAP] = {
.call = ip_set_swap,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname2_policy,
},
[IPSET_CMD_LIST] = {
.call = ip_set_dump,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_dump_policy,
},
[IPSET_CMD_SAVE] = {
.call = ip_set_dump,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy,
},
[IPSET_CMD_ADD] = {
.call = ip_set_uadd,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_adt_policy,
},
[IPSET_CMD_DEL] = {
.call = ip_set_udel,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_adt_policy,
},
[IPSET_CMD_TEST] = {
.call = ip_set_utest,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_adt_policy,
},
[IPSET_CMD_HEADER] = {
.call = ip_set_header,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy,
},
[IPSET_CMD_TYPE] = {
.call = ip_set_type,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_type_policy,
},
[IPSET_CMD_PROTOCOL] = {
.call = ip_set_protocol,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_protocol_policy,
},
[IPSET_CMD_GET_BYNAME] = {
.call = ip_set_byname,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_setname_policy,
},
[IPSET_CMD_GET_BYINDEX] = {
.call = ip_set_byindex,
+ .type = NFNL_CB_MUTEX,
.attr_count = IPSET_ATTR_CMD_MAX,
.policy = ip_set_index_policy,
},
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 44e3cb80e2e0..8690fc07030f 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1524,17 +1524,15 @@ static int ctnetlink_flush_conntrack(struct net *net,
return 0;
}
-static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int ctnetlink_del_conntrack(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
+ struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple;
- struct nf_conn *ct;
- struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nf_conntrack_zone zone;
+ struct nf_conn *ct;
int err;
err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
@@ -1550,15 +1548,15 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
else {
u_int8_t u3 = nfmsg->version ? nfmsg->nfgen_family : AF_UNSPEC;
- return ctnetlink_flush_conntrack(net, cda,
+ return ctnetlink_flush_conntrack(info->net, cda,
NETLINK_CB(skb).portid,
- nlmsg_report(nlh), u3);
+ nlmsg_report(info->nlh), u3);
}
if (err < 0)
return err;
- h = nf_conntrack_find_get(net, &zone, &tuple);
+ h = nf_conntrack_find_get(info->net, &zone, &tuple);
if (!h)
return -ENOENT;
@@ -1578,28 +1576,26 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
}
}
- nf_ct_delete(ct, NETLINK_CB(skb).portid, nlmsg_report(nlh));
+ nf_ct_delete(ct, NETLINK_CB(skb).portid, nlmsg_report(info->nlh));
nf_ct_put(ct);
return 0;
}
-static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int ctnetlink_get_conntrack(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
+ struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple;
- struct nf_conn *ct;
- struct sk_buff *skb2 = NULL;
- struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone;
+ struct sk_buff *skb2;
+ struct nf_conn *ct;
int err;
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.start = ctnetlink_start,
.dump = ctnetlink_dump_table,
@@ -1607,7 +1603,7 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
.data = (void *)cda,
};
- return netlink_dump_start(ctnl, skb, nlh, &c);
+ return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
@@ -1626,7 +1622,7 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
if (err < 0)
return err;
- h = nf_conntrack_find_get(net, &zone, &tuple);
+ h = nf_conntrack_find_get(info->net, &zone, &tuple);
if (!h)
return -ENOENT;
@@ -1639,13 +1635,16 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
return -ENOMEM;
}
- err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
- NFNL_MSG_TYPE(nlh->nlmsg_type), ct, true, 0);
+ err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).portid,
+ info->nlh->nlmsg_seq,
+ NFNL_MSG_TYPE(info->nlh->nlmsg_type), ct,
+ true, 0);
nf_ct_put(ct);
if (err <= 0)
goto free;
- err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
+ err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (err < 0)
goto out;
@@ -1743,18 +1742,16 @@ ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb)
return ctnetlink_dump_list(skb, cb, true);
}
-static int ctnetlink_get_ct_dying(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int ctnetlink_get_ct_dying(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = ctnetlink_dump_dying,
.done = ctnetlink_done_list,
};
- return netlink_dump_start(ctnl, skb, nlh, &c);
+ return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
return -EOPNOTSUPP;
@@ -1766,18 +1763,16 @@ ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb)
return ctnetlink_dump_list(skb, cb, false);
}
-static int ctnetlink_get_ct_unconfirmed(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int ctnetlink_get_ct_unconfirmed(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = ctnetlink_dump_unconfirmed,
.done = ctnetlink_done_list,
};
- return netlink_dump_start(ctnl, skb, nlh, &c);
+ return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
return -EOPNOTSUPP;
@@ -2374,18 +2369,16 @@ err1:
return ERR_PTR(err);
}
-static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int ctnetlink_new_conntrack(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
+ struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
struct nf_conntrack_tuple otuple, rtuple;
struct nf_conntrack_tuple_hash *h = NULL;
- struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- struct nf_conn *ct;
u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone;
+ struct nf_conn *ct;
int err;
err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
@@ -2407,13 +2400,13 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
}
if (cda[CTA_TUPLE_ORIG])
- h = nf_conntrack_find_get(net, &zone, &otuple);
+ h = nf_conntrack_find_get(info->net, &zone, &otuple);
else if (cda[CTA_TUPLE_REPLY])
- h = nf_conntrack_find_get(net, &zone, &rtuple);
+ h = nf_conntrack_find_get(info->net, &zone, &rtuple);
if (h == NULL) {
err = -ENOENT;
- if (nlh->nlmsg_flags & NLM_F_CREATE) {
+ if (info->nlh->nlmsg_flags & NLM_F_CREATE) {
enum ip_conntrack_events events;
if (!cda[CTA_TUPLE_ORIG] || !cda[CTA_TUPLE_REPLY])
@@ -2421,8 +2414,8 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
if (otuple.dst.protonum != rtuple.dst.protonum)
return -EINVAL;
- ct = ctnetlink_create_conntrack(net, &zone, cda, &otuple,
- &rtuple, u3);
+ ct = ctnetlink_create_conntrack(info->net, &zone, cda,
+ &otuple, &rtuple, u3);
if (IS_ERR(ct))
return PTR_ERR(ct);
@@ -2445,7 +2438,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
(1 << IPCT_SYNPROXY) |
events,
ct, NETLINK_CB(skb).portid,
- nlmsg_report(nlh));
+ nlmsg_report(info->nlh));
nf_ct_put(ct);
}
@@ -2455,7 +2448,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
err = -EEXIST;
ct = nf_ct_tuplehash_to_ctrack(h);
- if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
+ if (!(info->nlh->nlmsg_flags & NLM_F_EXCL)) {
err = ctnetlink_change_conntrack(ct, cda);
if (err == 0) {
nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
@@ -2467,7 +2460,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
(1 << IPCT_MARK) |
(1 << IPCT_SYNPROXY),
ct, NETLINK_CB(skb).portid,
- nlmsg_report(nlh));
+ nlmsg_report(info->nlh));
}
}
@@ -2539,17 +2532,15 @@ ctnetlink_ct_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
-static int ctnetlink_stat_ct_cpu(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int ctnetlink_stat_ct_cpu(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = ctnetlink_ct_stat_cpu_dump,
};
- return netlink_dump_start(ctnl, skb, nlh, &c);
+ return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
return 0;
@@ -2585,10 +2576,8 @@ nlmsg_failure:
return -1;
}
-static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int ctnetlink_stat_ct(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
struct sk_buff *skb2;
int err;
@@ -2598,13 +2587,14 @@ static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl,
return -ENOMEM;
err = ctnetlink_stat_ct_fill_info(skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq,
- NFNL_MSG_TYPE(nlh->nlmsg_type),
+ info->nlh->nlmsg_seq,
+ NFNL_MSG_TYPE(info->nlh->nlmsg_type),
sock_net(skb->sk));
if (err <= 0)
goto free;
- err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
+ err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (err < 0)
goto out;
@@ -3284,29 +3274,29 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
return err;
}
-static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int ctnetlink_get_expect(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
+ struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_tuple tuple;
struct nf_conntrack_expect *exp;
- struct sk_buff *skb2;
- struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone;
+ struct sk_buff *skb2;
int err;
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
if (cda[CTA_EXPECT_MASTER])
- return ctnetlink_dump_exp_ct(net, ctnl, skb, nlh, cda,
- extack);
+ return ctnetlink_dump_exp_ct(info->net, info->sk, skb,
+ info->nlh, cda,
+ info->extack);
else {
struct netlink_dump_control c = {
.dump = ctnetlink_exp_dump_table,
.done = ctnetlink_exp_done,
};
- return netlink_dump_start(ctnl, skb, nlh, &c);
+ return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
}
@@ -3326,7 +3316,7 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
if (err < 0)
return err;
- exp = nf_ct_expect_find_get(net, &zone, &tuple);
+ exp = nf_ct_expect_find_get(info->net, &zone, &tuple);
if (!exp)
return -ENOENT;
@@ -3348,13 +3338,15 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
rcu_read_lock();
err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, exp);
+ info->nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
+ exp);
rcu_read_unlock();
nf_ct_expect_put(exp);
if (err <= 0)
goto free;
- err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
+ err = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (err < 0)
goto out;
@@ -3382,15 +3374,14 @@ static bool expect_iter_all(struct nf_conntrack_expect *exp, void *data)
return true;
}
-static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int ctnetlink_del_expect(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
+ struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_expect *exp;
struct nf_conntrack_tuple tuple;
- struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone;
int err;
@@ -3406,7 +3397,7 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
return err;
/* bump usage count to 2 */
- exp = nf_ct_expect_find_get(net, &zone, &tuple);
+ exp = nf_ct_expect_find_get(info->net, &zone, &tuple);
if (!exp)
return -ENOENT;
@@ -3422,7 +3413,7 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
spin_lock_bh(&nf_conntrack_expect_lock);
if (del_timer(&exp->timeout)) {
nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid,
- nlmsg_report(nlh));
+ nlmsg_report(info->nlh));
nf_ct_expect_put(exp);
}
spin_unlock_bh(&nf_conntrack_expect_lock);
@@ -3432,14 +3423,14 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
} else if (cda[CTA_EXPECT_HELP_NAME]) {
char *name = nla_data(cda[CTA_EXPECT_HELP_NAME]);
- nf_ct_expect_iterate_net(net, expect_iter_name, name,
+ nf_ct_expect_iterate_net(info->net, expect_iter_name, name,
NETLINK_CB(skb).portid,
- nlmsg_report(nlh));
+ nlmsg_report(info->nlh));
} else {
/* This basically means we have to flush everything*/
- nf_ct_expect_iterate_net(net, expect_iter_all, NULL,
+ nf_ct_expect_iterate_net(info->net, expect_iter_all, NULL,
NETLINK_CB(skb).portid,
- nlmsg_report(nlh));
+ nlmsg_report(info->nlh));
}
return 0;
@@ -3635,15 +3626,14 @@ err_ct:
return err;
}
-static int ctnetlink_new_expect(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int ctnetlink_new_expect(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
+ struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_tuple tuple;
struct nf_conntrack_expect *exp;
- struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u_int8_t u3 = nfmsg->nfgen_family;
struct nf_conntrack_zone zone;
int err;
@@ -3662,20 +3652,20 @@ static int ctnetlink_new_expect(struct net *net, struct sock *ctnl,
return err;
spin_lock_bh(&nf_conntrack_expect_lock);
- exp = __nf_ct_expect_find(net, &zone, &tuple);
+ exp = __nf_ct_expect_find(info->net, &zone, &tuple);
if (!exp) {
spin_unlock_bh(&nf_conntrack_expect_lock);
err = -ENOENT;
- if (nlh->nlmsg_flags & NLM_F_CREATE) {
- err = ctnetlink_create_expect(net, &zone, cda, u3,
+ if (info->nlh->nlmsg_flags & NLM_F_CREATE) {
+ err = ctnetlink_create_expect(info->net, &zone, cda, u3,
NETLINK_CB(skb).portid,
- nlmsg_report(nlh));
+ nlmsg_report(info->nlh));
}
return err;
}
err = -EEXIST;
- if (!(nlh->nlmsg_flags & NLM_F_EXCL))
+ if (!(info->nlh->nlmsg_flags & NLM_F_EXCL))
err = ctnetlink_change_expect(exp, cda);
spin_unlock_bh(&nf_conntrack_expect_lock);
@@ -3736,17 +3726,15 @@ ctnetlink_exp_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
-static int ctnetlink_stat_exp_cpu(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int ctnetlink_stat_exp_cpu(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = ctnetlink_exp_stat_cpu_dump,
};
- return netlink_dump_start(ctnl, skb, nlh, &c);
+ return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
return 0;
@@ -3763,35 +3751,71 @@ static struct nf_exp_event_notifier ctnl_notifier_exp = {
#endif
static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
- [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack,
- .attr_count = CTA_MAX,
- .policy = ct_nla_policy },
- [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack,
- .attr_count = CTA_MAX,
- .policy = ct_nla_policy },
- [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack,
- .attr_count = CTA_MAX,
- .policy = ct_nla_policy },
- [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
- .attr_count = CTA_MAX,
- .policy = ct_nla_policy },
- [IPCTNL_MSG_CT_GET_STATS_CPU] = { .call = ctnetlink_stat_ct_cpu },
- [IPCTNL_MSG_CT_GET_STATS] = { .call = ctnetlink_stat_ct },
- [IPCTNL_MSG_CT_GET_DYING] = { .call = ctnetlink_get_ct_dying },
- [IPCTNL_MSG_CT_GET_UNCONFIRMED] = { .call = ctnetlink_get_ct_unconfirmed },
+ [IPCTNL_MSG_CT_NEW] = {
+ .call = ctnetlink_new_conntrack,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_MAX,
+ .policy = ct_nla_policy
+ },
+ [IPCTNL_MSG_CT_GET] = {
+ .call = ctnetlink_get_conntrack,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_MAX,
+ .policy = ct_nla_policy
+ },
+ [IPCTNL_MSG_CT_DELETE] = {
+ .call = ctnetlink_del_conntrack,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_MAX,
+ .policy = ct_nla_policy
+ },
+ [IPCTNL_MSG_CT_GET_CTRZERO] = {
+ .call = ctnetlink_get_conntrack,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_MAX,
+ .policy = ct_nla_policy
+ },
+ [IPCTNL_MSG_CT_GET_STATS_CPU] = {
+ .call = ctnetlink_stat_ct_cpu,
+ .type = NFNL_CB_MUTEX,
+ },
+ [IPCTNL_MSG_CT_GET_STATS] = {
+ .call = ctnetlink_stat_ct,
+ .type = NFNL_CB_MUTEX,
+ },
+ [IPCTNL_MSG_CT_GET_DYING] = {
+ .call = ctnetlink_get_ct_dying,
+ .type = NFNL_CB_MUTEX,
+ },
+ [IPCTNL_MSG_CT_GET_UNCONFIRMED] = {
+ .call = ctnetlink_get_ct_unconfirmed,
+ .type = NFNL_CB_MUTEX,
+ },
};
static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
- [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect,
- .attr_count = CTA_EXPECT_MAX,
- .policy = exp_nla_policy },
- [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect,
- .attr_count = CTA_EXPECT_MAX,
- .policy = exp_nla_policy },
- [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
- .attr_count = CTA_EXPECT_MAX,
- .policy = exp_nla_policy },
- [IPCTNL_MSG_EXP_GET_STATS_CPU] = { .call = ctnetlink_stat_exp_cpu },
+ [IPCTNL_MSG_EXP_GET] = {
+ .call = ctnetlink_get_expect,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_EXPECT_MAX,
+ .policy = exp_nla_policy
+ },
+ [IPCTNL_MSG_EXP_NEW] = {
+ .call = ctnetlink_new_expect,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_EXPECT_MAX,
+ .policy = exp_nla_policy
+ },
+ [IPCTNL_MSG_EXP_DELETE] = {
+ .call = ctnetlink_del_expect,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_EXPECT_MAX,
+ .policy = exp_nla_policy
+ },
+ [IPCTNL_MSG_EXP_GET_STATS_CPU] = {
+ .call = ctnetlink_stat_exp_cpu,
+ .type = NFNL_CB_MUTEX,
+ },
};
static const struct nfnetlink_subsystem ctnl_subsys = {
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 47e9319d2cf3..89e5bac384d7 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -536,15 +536,19 @@ static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
mutex_lock(&nf_ct_proto_mutex);
switch (nfproto) {
case NFPROTO_IPV4:
- if (cnet->users4 && (--cnet->users4 == 0))
+ if (cnet->users4 && (--cnet->users4 == 0)) {
nf_unregister_net_hooks(net, ipv4_conntrack_ops,
ARRAY_SIZE(ipv4_conntrack_ops));
+ nf_defrag_ipv4_disable(net);
+ }
break;
#if IS_ENABLED(CONFIG_IPV6)
case NFPROTO_IPV6:
- if (cnet->users6 && (--cnet->users6 == 0))
+ if (cnet->users6 && (--cnet->users6 == 0)) {
nf_unregister_net_hooks(net, ipv6_conntrack_ops,
ARRAY_SIZE(ipv6_conntrack_ops));
+ nf_defrag_ipv6_disable(net);
+ }
break;
#endif
case NFPROTO_BRIDGE:
diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c
index 2518818ed479..13234641cdb3 100644
--- a/net/netfilter/nf_log_syslog.c
+++ b/net/netfilter/nf_log_syslog.c
@@ -1011,6 +1011,7 @@ static void __net_exit nf_log_syslog_net_exit(struct net *net)
nf_log_unset(net, &nf_arp_logger);
nf_log_unset(net, &nf_ip6_logger);
nf_log_unset(net, &nf_netdev_logger);
+ nf_log_unset(net, &nf_bridge_logger);
}
static struct pernet_operations nf_log_syslog_net_ops = {
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index b7c3c902290f..7de595ead06a 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -146,43 +146,6 @@ static void __nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl)
return;
}
}
-
-int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
-{
- struct flowi fl;
- unsigned int hh_len;
- struct dst_entry *dst;
- struct sock *sk = skb->sk;
- int err;
-
- err = xfrm_decode_session(skb, &fl, family);
- if (err < 0)
- return err;
-
- dst = skb_dst(skb);
- if (dst->xfrm)
- dst = ((struct xfrm_dst *)dst)->route;
- if (!dst_hold_safe(dst))
- return -EHOSTUNREACH;
-
- if (sk && !net_eq(net, sock_net(sk)))
- sk = NULL;
-
- dst = xfrm_lookup(net, dst, &fl, sk, 0);
- if (IS_ERR(dst))
- return PTR_ERR(dst);
-
- skb_dst_drop(skb);
- skb_dst_set(skb, dst);
-
- /* Change in oif may mean change in hh_len. */
- hh_len = skb_dst(skb)->dev->hard_header_len;
- if (skb_headroom(skb) < hh_len &&
- pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
- return -ENOMEM;
- return 0;
-}
-EXPORT_SYMBOL(nf_xfrm_me_harder);
#endif /* CONFIG_XFRM */
/* We keep an extra hash for each conntrack, for fast searching. */
diff --git a/net/netfilter/nf_nat_proto.c b/net/netfilter/nf_nat_proto.c
index 4731d21fc3ad..48cc60084d28 100644
--- a/net/netfilter/nf_nat_proto.c
+++ b/net/netfilter/nf_nat_proto.c
@@ -659,6 +659,44 @@ nf_nat_ipv4_pre_routing(void *priv, struct sk_buff *skb,
return ret;
}
+#ifdef CONFIG_XFRM
+static int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
+{
+ struct sock *sk = skb->sk;
+ struct dst_entry *dst;
+ unsigned int hh_len;
+ struct flowi fl;
+ int err;
+
+ err = xfrm_decode_session(skb, &fl, family);
+ if (err < 0)
+ return err;
+
+ dst = skb_dst(skb);
+ if (dst->xfrm)
+ dst = ((struct xfrm_dst *)dst)->route;
+ if (!dst_hold_safe(dst))
+ return -EHOSTUNREACH;
+
+ if (sk && !net_eq(net, sock_net(sk)))
+ sk = NULL;
+
+ dst = xfrm_lookup(net, dst, &fl, sk, 0);
+ if (IS_ERR(dst))
+ return PTR_ERR(dst);
+
+ skb_dst_drop(skb);
+ skb_dst_set(skb, dst);
+
+ /* Change in oif may mean change in hh_len. */
+ hh_len = skb_dst(skb)->dev->hard_header_len;
+ if (skb_headroom(skb) < hh_len &&
+ pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
+ return -ENOMEM;
+ return 0;
+}
+#endif
+
static unsigned int
nf_nat_ipv4_local_in(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 357443b3c0e4..0b7fe0a902ff 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -21,7 +21,6 @@
#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_offload.h>
#include <net/net_namespace.h>
-#include <net/netns/generic.h>
#include <net/sock.h>
#define NFT_MODULE_AUTOLOAD_LIMIT (MODULE_NAME_LEN - sizeof("nft-expr-255-"))
@@ -106,7 +105,7 @@ static const u8 nft2audit_op[NFT_MSG_MAX] = { // enum nf_tables_msg_types
static void nft_validate_state_update(struct net *net, u8 new_validate_state)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
switch (nft_net->validate_state) {
case NFT_VALIDATE_SKIP:
@@ -181,7 +180,7 @@ static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
if (!nft_set_is_anonymous(set))
return;
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
list_for_each_entry_reverse(trans, &nft_net->commit_list, list) {
switch (trans->msg_type) {
case NFT_MSG_NEWSET:
@@ -278,9 +277,8 @@ static void nf_tables_unregister_hook(struct net *net,
static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *trans)
{
- struct nftables_pernet *nft_net;
+ struct nftables_pernet *nft_net = nft_pernet(net);
- nft_net = net_generic(net, nf_tables_net_id);
list_add_tail(&trans->list, &nft_net->commit_list);
}
@@ -566,7 +564,7 @@ static struct nft_table *nft_table_lookup(const struct net *net,
if (nla == NULL)
return ERR_PTR(-EINVAL);
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
list_for_each_entry_rcu(table, &nft_net->tables, list,
lockdep_is_held(&nft_net->commit_mutex)) {
if (!nla_strcmp(nla, table->name) &&
@@ -590,7 +588,7 @@ static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
struct nftables_pernet *nft_net;
struct nft_table *table;
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
list_for_each_entry(table, &nft_net->tables, list) {
if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
nft_active_genmask(table, genmask))
@@ -655,7 +653,7 @@ __printf(2, 3) int nft_request_module(struct net *net, const char *fmt,
if (ret >= MODULE_NAME_LEN)
return 0;
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
list_for_each_entry(req, &nft_net->module_list, list) {
if (!strcmp(req->module, module_name)) {
if (req->done)
@@ -711,7 +709,7 @@ nf_tables_chain_type_lookup(struct net *net, const struct nlattr *nla,
static __be16 nft_base_seq(const struct net *net)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
return htons(nft_net->base_seq & 0xffff);
}
@@ -793,7 +791,7 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
goto err;
}
- nft_net = net_generic(ctx->net, nf_tables_net_id);
+ nft_net = nft_pernet(ctx->net);
nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
return;
err:
@@ -811,7 +809,7 @@ static int nf_tables_dump_tables(struct sk_buff *skb,
int family = nfmsg->nfgen_family;
rcu_read_lock();
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
list_for_each_entry_rcu(table, &nft_net->tables, list) {
@@ -860,25 +858,25 @@ static int nft_netlink_dump_start_rcu(struct sock *nlsk, struct sk_buff *skb,
}
/* called with rcu_read_lock held */
-static int nf_tables_gettable(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_gettable(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_cur(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_cur(info->net);
+ int family = nfmsg->nfgen_family;
const struct nft_table *table;
+ struct net *net = info->net;
struct sk_buff *skb2;
- int family = nfmsg->nfgen_family;
int err;
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = nf_tables_dump_tables,
.module = THIS_MODULE,
};
- return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c);
+ return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
}
table = nft_table_lookup(net, nla[NFTA_TABLE_NAME], family, genmask, 0);
@@ -892,8 +890,8 @@ static int nf_tables_gettable(struct net *net, struct sock *nlsk,
return -ENOMEM;
err = nf_tables_fill_table_info(skb2, net, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
- family, table);
+ info->nlh->nlmsg_seq, NFT_MSG_NEWTABLE,
+ 0, family, table);
if (err < 0)
goto err_fill_table_info;
@@ -1057,15 +1055,15 @@ static int nft_objname_hash_cmp(struct rhashtable_compare_arg *arg,
return strcmp(obj->key.name, k->name);
}
-static int nf_tables_newtable(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_next(net);
+ struct nftables_pernet *nft_net = nft_pernet(info->net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_next(info->net);
int family = nfmsg->nfgen_family;
+ struct net *net = info->net;
const struct nlattr *attr;
struct nft_table *table;
struct nft_ctx ctx;
@@ -1080,14 +1078,15 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
if (PTR_ERR(table) != -ENOENT)
return PTR_ERR(table);
} else {
- if (nlh->nlmsg_flags & NLM_F_EXCL) {
+ if (info->nlh->nlmsg_flags & NLM_F_EXCL) {
NL_SET_BAD_ATTR(extack, attr);
return -EEXIST;
}
- if (nlh->nlmsg_flags & NLM_F_REPLACE)
+ if (info->nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP;
- nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
+
return nf_tables_updtable(&ctx);
}
@@ -1128,7 +1127,7 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
if (table->flags & NFT_TABLE_F_OWNER)
table->nlpid = NETLINK_CB(skb).portid;
- nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
if (err < 0)
goto err_trans;
@@ -1221,9 +1220,9 @@ out:
static int nft_flush(struct nft_ctx *ctx, int family)
{
- struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
- struct nft_table *table, *nt;
+ struct nftables_pernet *nft_net = nft_pernet(ctx->net);
const struct nlattr * const *nla = ctx->nla;
+ struct nft_table *table, *nt;
int err = 0;
list_for_each_entry_safe(table, nt, &nft_net->tables, list) {
@@ -1252,19 +1251,19 @@ out:
return err;
}
-static int nf_tables_deltable(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_next(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_next(info->net);
int family = nfmsg->nfgen_family;
+ struct net *net = info->net;
const struct nlattr *attr;
struct nft_table *table;
struct nft_ctx ctx;
- nft_ctx_init(&ctx, net, skb, nlh, 0, NULL, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, 0, NULL, NULL, nla);
if (family == AF_UNSPEC ||
(!nla[NFTA_TABLE_NAME] && !nla[NFTA_TABLE_HANDLE]))
return nft_flush(&ctx, family);
@@ -1283,7 +1282,7 @@ static int nf_tables_deltable(struct net *net, struct sock *nlsk,
return PTR_ERR(table);
}
- if (nlh->nlmsg_flags & NLM_F_NONREC &&
+ if (info->nlh->nlmsg_flags & NLM_F_NONREC &&
table->use > 0)
return -EBUSY;
@@ -1345,7 +1344,7 @@ nft_chain_lookup_byhandle(const struct nft_table *table, u64 handle, u8 genmask)
static bool lockdep_commit_lock_is_held(const struct net *net)
{
#ifdef CONFIG_PROVE_LOCKING
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
return lockdep_is_held(&nft_net->commit_mutex);
#else
@@ -1570,7 +1569,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
goto err;
}
- nft_net = net_generic(ctx->net, nf_tables_net_id);
+ nft_net = nft_pernet(ctx->net);
nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
return;
err:
@@ -1581,15 +1580,15 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
struct netlink_callback *cb)
{
const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
- const struct nft_table *table;
- const struct nft_chain *chain;
unsigned int idx = 0, s_idx = cb->args[0];
struct net *net = sock_net(skb->sk);
int family = nfmsg->nfgen_family;
struct nftables_pernet *nft_net;
+ const struct nft_table *table;
+ const struct nft_chain *chain;
rcu_read_lock();
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
list_for_each_entry_rcu(table, &nft_net->tables, list) {
@@ -1625,26 +1624,26 @@ done:
}
/* called with rcu_read_lock held */
-static int nf_tables_getchain(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_getchain(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_cur(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_cur(info->net);
+ int family = nfmsg->nfgen_family;
const struct nft_chain *chain;
+ struct net *net = info->net;
struct nft_table *table;
struct sk_buff *skb2;
- int family = nfmsg->nfgen_family;
int err;
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = nf_tables_dump_chains,
.module = THIS_MODULE,
};
- return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c);
+ return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
}
table = nft_table_lookup(net, nla[NFTA_CHAIN_TABLE], family, genmask, 0);
@@ -1664,8 +1663,8 @@ static int nf_tables_getchain(struct net *net, struct sock *nlsk,
return -ENOMEM;
err = nf_tables_fill_chain_info(skb2, net, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
- family, table, chain);
+ info->nlh->nlmsg_seq, NFT_MSG_NEWCHAIN,
+ 0, family, table, chain);
if (err < 0)
goto err_fill_chain_info;
@@ -1908,7 +1907,7 @@ static int nft_chain_parse_hook(struct net *net,
struct nft_chain_hook *hook, u8 family,
bool autoload)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nlattr *ha[NFTA_HOOK_MAX + 1];
const struct nft_chain_type *type;
int err;
@@ -2302,7 +2301,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
if (nla[NFTA_CHAIN_HANDLE] &&
nla[NFTA_CHAIN_NAME]) {
- struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct nft_trans *tmp;
char *name;
@@ -2338,7 +2337,7 @@ err:
static struct nft_chain *nft_chain_lookup_byid(const struct net *net,
const struct nlattr *nla)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
u32 id = ntohl(nla_get_be32(nla));
struct nft_trans *trans;
@@ -2352,16 +2351,16 @@ static struct nft_chain *nft_chain_lookup_byid(const struct net *net,
return ERR_PTR(-ENOENT);
}
-static int nf_tables_newchain(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_next(net);
+ struct nftables_pernet *nft_net = nft_pernet(info->net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_next(info->net);
int family = nfmsg->nfgen_family;
struct nft_chain *chain = NULL;
+ struct net *net = info->net;
const struct nlattr *attr;
struct nft_table *table;
u8 policy = NF_ACCEPT;
@@ -2433,14 +2432,14 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
if (flags & ~NFT_CHAIN_FLAGS)
return -EOPNOTSUPP;
- nft_ctx_init(&ctx, net, skb, nlh, family, table, chain, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);
if (chain != NULL) {
- if (nlh->nlmsg_flags & NLM_F_EXCL) {
+ if (info->nlh->nlmsg_flags & NLM_F_EXCL) {
NL_SET_BAD_ATTR(extack, attr);
return -EEXIST;
}
- if (nlh->nlmsg_flags & NLM_F_REPLACE)
+ if (info->nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP;
flags |= chain->flags & NFT_CHAIN_BASE;
@@ -2451,14 +2450,14 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
return nf_tables_addchain(&ctx, family, genmask, policy, flags);
}
-static int nf_tables_delchain(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_next(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_next(info->net);
int family = nfmsg->nfgen_family;
+ struct net *net = info->net;
const struct nlattr *attr;
struct nft_table *table;
struct nft_chain *chain;
@@ -2488,11 +2487,11 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk,
return PTR_ERR(chain);
}
- if (nlh->nlmsg_flags & NLM_F_NONREC &&
+ if (info->nlh->nlmsg_flags & NLM_F_NONREC &&
chain->use > 0)
return -EBUSY;
- nft_ctx_init(&ctx, net, skb, nlh, family, table, chain, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);
use = chain->use;
list_for_each_entry(rule, &chain->rules, list) {
@@ -2715,15 +2714,15 @@ err1:
}
static int nf_tables_newexpr(const struct nft_ctx *ctx,
- const struct nft_expr_info *info,
+ const struct nft_expr_info *expr_info,
struct nft_expr *expr)
{
- const struct nft_expr_ops *ops = info->ops;
+ const struct nft_expr_ops *ops = expr_info->ops;
int err;
expr->ops = ops;
if (ops->init) {
- err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
+ err = ops->init(ctx, expr, (const struct nlattr **)expr_info->tb);
if (err < 0)
goto err1;
}
@@ -2747,21 +2746,21 @@ static void nf_tables_expr_destroy(const struct nft_ctx *ctx,
static struct nft_expr *nft_expr_init(const struct nft_ctx *ctx,
const struct nlattr *nla)
{
- struct nft_expr_info info;
+ struct nft_expr_info expr_info;
struct nft_expr *expr;
struct module *owner;
int err;
- err = nf_tables_expr_parse(ctx, nla, &info);
+ err = nf_tables_expr_parse(ctx, nla, &expr_info);
if (err < 0)
goto err1;
err = -ENOMEM;
- expr = kzalloc(info.ops->size, GFP_KERNEL);
+ expr = kzalloc(expr_info.ops->size, GFP_KERNEL);
if (expr == NULL)
goto err2;
- err = nf_tables_newexpr(ctx, &info, expr);
+ err = nf_tables_newexpr(ctx, &expr_info, expr);
if (err < 0)
goto err3;
@@ -2769,9 +2768,9 @@ static struct nft_expr *nft_expr_init(const struct nft_ctx *ctx,
err3:
kfree(expr);
err2:
- owner = info.ops->type->owner;
- if (info.ops->type->release_ops)
- info.ops->type->release_ops(info.ops);
+ owner = expr_info.ops->type->owner;
+ if (expr_info.ops->type->release_ops)
+ expr_info.ops->type->release_ops(expr_info.ops);
module_put(owner);
err1:
@@ -2908,7 +2907,7 @@ nla_put_failure:
static void nf_tables_rule_notify(const struct nft_ctx *ctx,
const struct nft_rule *rule, int event)
{
- struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct sk_buff *skb;
int err;
@@ -2989,7 +2988,7 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
struct nftables_pernet *nft_net;
rcu_read_lock();
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
list_for_each_entry_rcu(table, &nft_net->tables, list) {
@@ -3078,21 +3077,21 @@ static int nf_tables_dump_rules_done(struct netlink_callback *cb)
}
/* called with rcu_read_lock held */
-static int nf_tables_getrule(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_cur(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_cur(info->net);
+ int family = nfmsg->nfgen_family;
const struct nft_chain *chain;
const struct nft_rule *rule;
+ struct net *net = info->net;
struct nft_table *table;
struct sk_buff *skb2;
- int family = nfmsg->nfgen_family;
int err;
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.start= nf_tables_dump_rules_start,
.dump = nf_tables_dump_rules,
@@ -3101,7 +3100,7 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
.data = (void *)nla,
};
- return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c);
+ return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
}
table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask, 0);
@@ -3127,7 +3126,7 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
return -ENOMEM;
err = nf_tables_fill_rule_info(skb2, net, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
+ info->nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
family, table, chain, rule, NULL);
if (err < 0)
goto err_fill_rule_info;
@@ -3218,28 +3217,28 @@ static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
#define NFT_RULE_MAXEXPRS 128
-static int nf_tables_newrule(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_next(net);
- struct nft_expr_info *info = NULL;
+ struct nftables_pernet *nft_net = nft_pernet(info->net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ unsigned int size, i, n, ulen = 0, usize = 0;
+ u8 genmask = nft_genmask_next(info->net);
+ struct nft_rule *rule, *old_rule = NULL;
+ struct nft_expr_info *expr_info = NULL;
int family = nfmsg->nfgen_family;
+ struct net *net = info->net;
struct nft_flow_rule *flow;
+ struct nft_userdata *udata;
struct nft_table *table;
struct nft_chain *chain;
- struct nft_rule *rule, *old_rule = NULL;
- struct nft_userdata *udata;
- struct nft_trans *trans = NULL;
+ struct nft_trans *trans;
+ u64 handle, pos_handle;
struct nft_expr *expr;
struct nft_ctx ctx;
struct nlattr *tmp;
- unsigned int size, i, n, ulen = 0, usize = 0;
int err, rem;
- u64 handle, pos_handle;
lockdep_assert_held(&nft_net->commit_mutex);
@@ -3278,17 +3277,17 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
return PTR_ERR(rule);
}
- if (nlh->nlmsg_flags & NLM_F_EXCL) {
+ if (info->nlh->nlmsg_flags & NLM_F_EXCL) {
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_HANDLE]);
return -EEXIST;
}
- if (nlh->nlmsg_flags & NLM_F_REPLACE)
+ if (info->nlh->nlmsg_flags & NLM_F_REPLACE)
old_rule = rule;
else
return -EOPNOTSUPP;
} else {
- if (!(nlh->nlmsg_flags & NLM_F_CREATE) ||
- nlh->nlmsg_flags & NLM_F_REPLACE)
+ if (!(info->nlh->nlmsg_flags & NLM_F_CREATE) ||
+ info->nlh->nlmsg_flags & NLM_F_REPLACE)
return -EINVAL;
handle = nf_tables_alloc_handle(table);
@@ -3311,15 +3310,15 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
}
}
- nft_ctx_init(&ctx, net, skb, nlh, family, table, chain, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);
n = 0;
size = 0;
if (nla[NFTA_RULE_EXPRESSIONS]) {
- info = kvmalloc_array(NFT_RULE_MAXEXPRS,
- sizeof(struct nft_expr_info),
- GFP_KERNEL);
- if (!info)
+ expr_info = kvmalloc_array(NFT_RULE_MAXEXPRS,
+ sizeof(struct nft_expr_info),
+ GFP_KERNEL);
+ if (!expr_info)
return -ENOMEM;
nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
@@ -3328,10 +3327,10 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
goto err1;
if (n == NFT_RULE_MAXEXPRS)
goto err1;
- err = nf_tables_expr_parse(&ctx, tmp, &info[n]);
+ err = nf_tables_expr_parse(&ctx, tmp, &expr_info[n]);
if (err < 0)
goto err1;
- size += info[n].ops->size;
+ size += expr_info[n].ops->size;
n++;
}
}
@@ -3365,20 +3364,20 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
expr = nft_expr_first(rule);
for (i = 0; i < n; i++) {
- err = nf_tables_newexpr(&ctx, &info[i], expr);
+ err = nf_tables_newexpr(&ctx, &expr_info[i], expr);
if (err < 0) {
- NL_SET_BAD_ATTR(extack, info[i].attr);
+ NL_SET_BAD_ATTR(extack, expr_info[i].attr);
goto err2;
}
- if (info[i].ops->validate)
+ if (expr_info[i].ops->validate)
nft_validate_state_update(net, NFT_VALIDATE_NEED);
- info[i].ops = NULL;
+ expr_info[i].ops = NULL;
expr = nft_expr_next(expr);
}
- if (nlh->nlmsg_flags & NLM_F_REPLACE) {
+ if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule);
if (trans == NULL) {
err = -ENOMEM;
@@ -3398,7 +3397,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
goto err2;
}
- if (nlh->nlmsg_flags & NLM_F_APPEND) {
+ if (info->nlh->nlmsg_flags & NLM_F_APPEND) {
if (old_rule)
list_add_rcu(&rule->list, &old_rule->list);
else
@@ -3410,7 +3409,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
list_add_rcu(&rule->list, &chain->rules);
}
}
- kvfree(info);
+ kvfree(expr_info);
chain->use++;
if (nft_net->validate_state == NFT_VALIDATE_DO)
@@ -3429,20 +3428,21 @@ err2:
nf_tables_rule_release(&ctx, rule);
err1:
for (i = 0; i < n; i++) {
- if (info[i].ops) {
- module_put(info[i].ops->type->owner);
- if (info[i].ops->type->release_ops)
- info[i].ops->type->release_ops(info[i].ops);
+ if (expr_info[i].ops) {
+ module_put(expr_info[i].ops->type->owner);
+ if (expr_info[i].ops->type->release_ops)
+ expr_info[i].ops->type->release_ops(expr_info[i].ops);
}
}
- kvfree(info);
+ kvfree(expr_info);
+
return err;
}
static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
const struct nlattr *nla)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
u32 id = ntohl(nla_get_be32(nla));
struct nft_trans *trans;
@@ -3456,17 +3456,17 @@ static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
return ERR_PTR(-ENOENT);
}
-static int nf_tables_delrule(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_next(net);
- struct nft_table *table;
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ int family = nfmsg->nfgen_family, err = 0;
+ u8 genmask = nft_genmask_next(info->net);
struct nft_chain *chain = NULL;
+ struct net *net = info->net;
+ struct nft_table *table;
struct nft_rule *rule;
- int family = nfmsg->nfgen_family, err = 0;
struct nft_ctx ctx;
table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask,
@@ -3487,7 +3487,7 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
return -EOPNOTSUPP;
}
- nft_ctx_init(&ctx, net, skb, nlh, family, table, chain, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);
if (chain) {
if (nla[NFTA_RULE_HANDLE]) {
@@ -3559,7 +3559,7 @@ nft_select_set_ops(const struct nft_ctx *ctx,
const struct nft_set_desc *desc,
enum nft_set_policies policy)
{
- struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(ctx->net);
const struct nft_set_ops *ops, *bops;
struct nft_set_estimate est, best;
const struct nft_set_type *type;
@@ -3704,9 +3704,9 @@ static struct nft_set *nft_set_lookup_byhandle(const struct nft_table *table,
static struct nft_set *nft_set_lookup_byid(const struct net *net,
const struct nlattr *nla, u8 genmask)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
- struct nft_trans *trans;
+ struct nftables_pernet *nft_net = nft_pernet(net);
u32 id = ntohl(nla_get_be32(nla));
+ struct nft_trans *trans;
list_for_each_entry(trans, &nft_net->commit_list, list) {
if (trans->msg_type == NFT_MSG_NEWSET) {
@@ -3942,7 +3942,7 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx,
const struct nft_set *set, int event,
gfp_t gfp_flags)
{
- struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct sk_buff *skb;
u32 portid = ctx->portid;
int err;
@@ -3980,7 +3980,7 @@ static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
rcu_read_lock();
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
list_for_each_entry_rcu(table, &nft_net->tables, list) {
@@ -4047,25 +4047,25 @@ static int nf_tables_dump_sets_done(struct netlink_callback *cb)
}
/* called with rcu_read_lock held */
-static int nf_tables_getset(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_getset(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- u8 genmask = nft_genmask_cur(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_cur(info->net);
+ struct net *net = info->net;
const struct nft_set *set;
- struct nft_ctx ctx;
struct sk_buff *skb2;
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ struct nft_ctx ctx;
int err;
/* Verify existence before starting dump */
- err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla, extack,
+ err = nft_ctx_init_from_setattr(&ctx, net, skb, info->nlh, nla, extack,
genmask, 0);
if (err < 0)
return err;
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.start = nf_tables_dump_sets_start,
.dump = nf_tables_dump_sets,
@@ -4074,7 +4074,7 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
.module = THIS_MODULE,
};
- return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c);
+ return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
}
/* Only accept unspec with dump */
@@ -4168,28 +4168,27 @@ static int nf_tables_set_desc_parse(struct nft_set_desc *desc,
return err;
}
-static int nf_tables_newset(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_next(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ u32 ktype, dtype, flags, policy, gc_int, objtype;
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_next(info->net);
int family = nfmsg->nfgen_family;
const struct nft_set_ops *ops;
struct nft_expr *expr = NULL;
+ struct net *net = info->net;
+ struct nft_set_desc desc;
struct nft_table *table;
+ unsigned char *udata;
struct nft_set *set;
struct nft_ctx ctx;
- char *name;
- u64 size;
u64 timeout;
- u32 ktype, dtype, flags, policy, gc_int, objtype;
- struct nft_set_desc desc;
- unsigned char *udata;
+ char *name;
+ int err, i;
u16 udlen;
- int err;
- int i;
+ u64 size;
if (nla[NFTA_SET_TABLE] == NULL ||
nla[NFTA_SET_NAME] == NULL ||
@@ -4297,7 +4296,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
return PTR_ERR(table);
}
- nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
set = nft_set_lookup(table, nla[NFTA_SET_NAME], genmask);
if (IS_ERR(set)) {
@@ -4306,17 +4305,17 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
return PTR_ERR(set);
}
} else {
- if (nlh->nlmsg_flags & NLM_F_EXCL) {
+ if (info->nlh->nlmsg_flags & NLM_F_EXCL) {
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_NAME]);
return -EEXIST;
}
- if (nlh->nlmsg_flags & NLM_F_REPLACE)
+ if (info->nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP;
return 0;
}
- if (!(nlh->nlmsg_flags & NLM_F_CREATE))
+ if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
return -ENOENT;
ops = nft_select_set_ops(&ctx, nla, &desc, policy);
@@ -4390,6 +4389,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
}
INIT_LIST_HEAD(&set->bindings);
+ INIT_LIST_HEAD(&set->catchall_list);
set->table = table;
write_pnet(&set->net, net);
set->ops = ops;
@@ -4435,6 +4435,24 @@ err_set_name:
return err;
}
+struct nft_set_elem_catchall {
+ struct list_head list;
+ struct rcu_head rcu;
+ void *elem;
+};
+
+static void nft_set_catchall_destroy(const struct nft_ctx *ctx,
+ struct nft_set *set)
+{
+ struct nft_set_elem_catchall *catchall;
+
+ list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+ list_del_rcu(&catchall->list);
+ nft_set_elem_destroy(set, catchall->elem, true);
+ kfree_rcu(catchall);
+ }
+}
+
static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
{
int i;
@@ -4446,17 +4464,18 @@ static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
nft_expr_destroy(ctx, set->exprs[i]);
set->ops->destroy(set);
+ nft_set_catchall_destroy(ctx, set);
kfree(set->name);
kvfree(set);
}
-static int nf_tables_delset(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_delset(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_next(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_next(info->net);
+ struct net *net = info->net;
const struct nlattr *attr;
struct nft_set *set;
struct nft_ctx ctx;
@@ -4467,7 +4486,7 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
if (nla[NFTA_SET_TABLE] == NULL)
return -EINVAL;
- err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla, extack,
+ err = nft_ctx_init_from_setattr(&ctx, net, skb, info->nlh, nla, extack,
genmask, NETLINK_CB(skb).portid);
if (err < 0)
return err;
@@ -4485,7 +4504,8 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
return PTR_ERR(set);
}
if (set->use ||
- (nlh->nlmsg_flags & NLM_F_NONREC && atomic_read(&set->nelems) > 0)) {
+ (info->nlh->nlmsg_flags & NLM_F_NONREC &&
+ atomic_read(&set->nelems) > 0)) {
NL_SET_BAD_ATTR(extack, attr);
return -EBUSY;
}
@@ -4499,10 +4519,9 @@ static int nft_validate_register_store(const struct nft_ctx *ctx,
enum nft_data_types type,
unsigned int len);
-static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
- struct nft_set *set,
- const struct nft_set_iter *iter,
- struct nft_set_elem *elem)
+static int nft_setelem_data_validate(const struct nft_ctx *ctx,
+ struct nft_set *set,
+ struct nft_set_elem *elem)
{
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
enum nft_registers dreg;
@@ -4514,6 +4533,37 @@ static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
set->dlen);
}
+static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
+ struct nft_set *set,
+ const struct nft_set_iter *iter,
+ struct nft_set_elem *elem)
+{
+ return nft_setelem_data_validate(ctx, set, elem);
+}
+
+static int nft_set_catchall_bind_check(const struct nft_ctx *ctx,
+ struct nft_set *set)
+{
+ u8 genmask = nft_genmask_next(ctx->net);
+ struct nft_set_elem_catchall *catchall;
+ struct nft_set_elem elem;
+ struct nft_set_ext *ext;
+ int ret = 0;
+
+ list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+ ext = nft_set_elem_ext(set, catchall->elem);
+ if (!nft_set_elem_active(ext, genmask))
+ continue;
+
+ elem.priv = catchall->elem;
+ ret = nft_setelem_data_validate(ctx, set, &elem);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_binding *binding)
{
@@ -4543,6 +4593,9 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
iter.fn = nf_tables_bind_check_setelem;
set->ops->walk(ctx, set, &iter);
+ if (!iter.err)
+ iter.err = nft_set_catchall_bind_check(ctx, set);
+
if (iter.err < 0)
return iter.err;
}
@@ -4729,7 +4782,8 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
if (nest == NULL)
goto nla_put_failure;
- if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, nft_set_ext_key(ext),
+ if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY) &&
+ nft_data_dump(skb, NFTA_SET_ELEM_KEY, nft_set_ext_key(ext),
NFT_DATA_VALUE, set->klen) < 0)
goto nla_put_failure;
@@ -4818,6 +4872,29 @@ struct nft_set_dump_ctx {
struct nft_ctx ctx;
};
+static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb,
+ const struct nft_set *set)
+{
+ struct nft_set_elem_catchall *catchall;
+ u8 genmask = nft_genmask_cur(net);
+ struct nft_set_elem elem;
+ struct nft_set_ext *ext;
+ int ret = 0;
+
+ list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+ ext = nft_set_elem_ext(set, catchall->elem);
+ if (!nft_set_elem_active(ext, genmask) ||
+ nft_set_elem_expired(ext))
+ continue;
+
+ elem.priv = catchall->elem;
+ ret = nf_tables_fill_setelem(skb, set, &elem);
+ break;
+ }
+
+ return ret;
+}
+
static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
{
struct nft_set_dump_ctx *dump_ctx = cb->data;
@@ -4833,7 +4910,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
int event;
rcu_read_lock();
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (dump_ctx->ctx.family != NFPROTO_UNSPEC &&
dump_ctx->ctx.family != table->family)
@@ -4882,6 +4959,9 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
args.iter.err = 0;
args.iter.fn = nf_tables_dump_setelem;
set->ops->walk(&dump_ctx->ctx, set, &args.iter);
+
+ if (!args.iter.err && args.iter.count == cb->args[0])
+ args.iter.err = nft_set_catchall_dump(net, skb, set);
rcu_read_unlock();
nla_nest_end(skb, nest);
@@ -4961,8 +5041,8 @@ static int nft_setelem_parse_flags(const struct nft_set *set,
return 0;
*flags = ntohl(nla_get_be32(attr));
- if (*flags & ~NFT_SET_ELEM_INTERVAL_END)
- return -EINVAL;
+ if (*flags & ~(NFT_SET_ELEM_INTERVAL_END | NFT_SET_ELEM_CATCHALL))
+ return -EOPNOTSUPP;
if (!(set->flags & NFT_SET_INTERVAL) &&
*flags & NFT_SET_ELEM_INTERVAL_END)
return -EINVAL;
@@ -5007,6 +5087,46 @@ static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set,
return 0;
}
+static void *nft_setelem_catchall_get(const struct net *net,
+ const struct nft_set *set)
+{
+ struct nft_set_elem_catchall *catchall;
+ u8 genmask = nft_genmask_cur(net);
+ struct nft_set_ext *ext;
+ void *priv = NULL;
+
+ list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+ ext = nft_set_elem_ext(set, catchall->elem);
+ if (!nft_set_elem_active(ext, genmask) ||
+ nft_set_elem_expired(ext))
+ continue;
+
+ priv = catchall->elem;
+ break;
+ }
+
+ return priv;
+}
+
+static int nft_setelem_get(struct nft_ctx *ctx, struct nft_set *set,
+ struct nft_set_elem *elem, u32 flags)
+{
+ void *priv;
+
+ if (!(flags & NFT_SET_ELEM_CATCHALL)) {
+ priv = set->ops->get(ctx->net, set, elem, flags);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+ } else {
+ priv = nft_setelem_catchall_get(ctx->net, set);
+ if (!priv)
+ return -ENOENT;
+ }
+ elem->priv = priv;
+
+ return 0;
+}
+
static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr)
{
@@ -5014,7 +5134,6 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_elem elem;
struct sk_buff *skb;
uint32_t flags = 0;
- void *priv;
int err;
err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr,
@@ -5022,17 +5141,19 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (err < 0)
return err;
- if (!nla[NFTA_SET_ELEM_KEY])
- return -EINVAL;
-
err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags);
if (err < 0)
return err;
- err = nft_setelem_parse_key(ctx, set, &elem.key.val,
- nla[NFTA_SET_ELEM_KEY]);
- if (err < 0)
- return err;
+ if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
+ return -EINVAL;
+
+ if (nla[NFTA_SET_ELEM_KEY]) {
+ err = nft_setelem_parse_key(ctx, set, &elem.key.val,
+ nla[NFTA_SET_ELEM_KEY]);
+ if (err < 0)
+ return err;
+ }
if (nla[NFTA_SET_ELEM_KEY_END]) {
err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
@@ -5041,11 +5162,9 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
return err;
}
- priv = set->ops->get(ctx->net, set, &elem, flags);
- if (IS_ERR(priv))
- return PTR_ERR(priv);
-
- elem.priv = priv;
+ err = nft_setelem_get(ctx, set, &elem, flags);
+ if (err < 0)
+ return err;
err = -ENOMEM;
skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
@@ -5065,18 +5184,19 @@ err_fill_setelem:
}
/* called with rcu_read_lock held */
-static int nf_tables_getsetelem(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_getsetelem(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- u8 genmask = nft_genmask_cur(net);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_cur(info->net);
+ struct net *net = info->net;
struct nft_set *set;
struct nlattr *attr;
struct nft_ctx ctx;
int rem, err = 0;
- err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, extack,
+ err = nft_ctx_init_from_elemattr(&ctx, net, skb, info->nlh, nla, extack,
genmask, NETLINK_CB(skb).portid);
if (err < 0)
return err;
@@ -5085,7 +5205,7 @@ static int nf_tables_getsetelem(struct net *net, struct sock *nlsk,
if (IS_ERR(set))
return PTR_ERR(set);
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.start = nf_tables_dump_set_start,
.dump = nf_tables_dump_set,
@@ -5098,7 +5218,7 @@ static int nf_tables_getsetelem(struct net *net, struct sock *nlsk,
};
c.data = &dump_ctx;
- return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c);
+ return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
}
if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS])
@@ -5138,7 +5258,7 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx,
goto err;
}
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
return;
err:
@@ -5204,7 +5324,8 @@ void *nft_set_elem_init(const struct nft_set *set,
ext = nft_set_elem_ext(set, elem);
nft_set_ext_init(ext, tmpl);
- memcpy(nft_set_ext_key(ext), key, set->klen);
+ if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY))
+ memcpy(nft_set_ext_key(ext), key, set->klen);
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
memcpy(nft_set_ext_key_end(ext), key_end, set->klen);
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
@@ -5262,8 +5383,8 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
}
EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
-/* Only called from commit path, nft_set_elem_deactivate() already deals with
- * the refcounting from the preparation phase.
+/* Only called from commit path, nft_setelem_data_deactivate() already deals
+ * with the refcounting from the preparation phase.
*/
static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
const struct nft_set *set, void *elem)
@@ -5335,6 +5456,192 @@ err_elem_expr_setup:
return -ENOMEM;
}
+struct nft_set_ext *nft_set_catchall_lookup(const struct net *net,
+ const struct nft_set *set)
+{
+ struct nft_set_elem_catchall *catchall;
+ u8 genmask = nft_genmask_cur(net);
+ struct nft_set_ext *ext;
+
+ list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+ ext = nft_set_elem_ext(set, catchall->elem);
+ if (nft_set_elem_active(ext, genmask) &&
+ !nft_set_elem_expired(ext))
+ return ext;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(nft_set_catchall_lookup);
+
+void *nft_set_catchall_gc(const struct nft_set *set)
+{
+ struct nft_set_elem_catchall *catchall, *next;
+ struct nft_set_ext *ext;
+ void *elem = NULL;
+
+ list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
+ ext = nft_set_elem_ext(set, catchall->elem);
+
+ if (!nft_set_elem_expired(ext) ||
+ nft_set_elem_mark_busy(ext))
+ continue;
+
+ elem = catchall->elem;
+ list_del_rcu(&catchall->list);
+ kfree_rcu(catchall, rcu);
+ break;
+ }
+
+ return elem;
+}
+EXPORT_SYMBOL_GPL(nft_set_catchall_gc);
+
+static int nft_setelem_catchall_insert(const struct net *net,
+ struct nft_set *set,
+ const struct nft_set_elem *elem,
+ struct nft_set_ext **pext)
+{
+ struct nft_set_elem_catchall *catchall;
+ u8 genmask = nft_genmask_next(net);
+ struct nft_set_ext *ext;
+
+ list_for_each_entry(catchall, &set->catchall_list, list) {
+ ext = nft_set_elem_ext(set, catchall->elem);
+ if (nft_set_elem_active(ext, genmask)) {
+ *pext = ext;
+ return -EEXIST;
+ }
+ }
+
+ catchall = kmalloc(sizeof(*catchall), GFP_KERNEL);
+ if (!catchall)
+ return -ENOMEM;
+
+ catchall->elem = elem->priv;
+ list_add_tail_rcu(&catchall->list, &set->catchall_list);
+
+ return 0;
+}
+
+static int nft_setelem_insert(const struct net *net,
+ struct nft_set *set,
+ const struct nft_set_elem *elem,
+ struct nft_set_ext **ext, unsigned int flags)
+{
+ int ret;
+
+ if (flags & NFT_SET_ELEM_CATCHALL)
+ ret = nft_setelem_catchall_insert(net, set, elem, ext);
+ else
+ ret = set->ops->insert(net, set, elem, ext);
+
+ return ret;
+}
+
+static bool nft_setelem_is_catchall(const struct nft_set *set,
+ const struct nft_set_elem *elem)
+{
+ struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
+
+ if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
+ *nft_set_ext_flags(ext) & NFT_SET_ELEM_CATCHALL)
+ return true;
+
+ return false;
+}
+
+static void nft_setelem_activate(struct net *net, struct nft_set *set,
+ struct nft_set_elem *elem)
+{
+ struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
+
+ if (nft_setelem_is_catchall(set, elem)) {
+ nft_set_elem_change_active(net, set, ext);
+ nft_set_elem_clear_busy(ext);
+ } else {
+ set->ops->activate(net, set, elem);
+ }
+}
+
+static int nft_setelem_catchall_deactivate(const struct net *net,
+ struct nft_set *set,
+ struct nft_set_elem *elem)
+{
+ struct nft_set_elem_catchall *catchall;
+ struct nft_set_ext *ext;
+
+ list_for_each_entry(catchall, &set->catchall_list, list) {
+ ext = nft_set_elem_ext(set, catchall->elem);
+ if (!nft_is_active(net, ext) ||
+ nft_set_elem_mark_busy(ext))
+ continue;
+
+ kfree(elem->priv);
+ elem->priv = catchall->elem;
+ nft_set_elem_change_active(net, set, ext);
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+static int __nft_setelem_deactivate(const struct net *net,
+ struct nft_set *set,
+ struct nft_set_elem *elem)
+{
+ void *priv;
+
+ priv = set->ops->deactivate(net, set, elem);
+ if (!priv)
+ return -ENOENT;
+
+ kfree(elem->priv);
+ elem->priv = priv;
+ set->ndeact++;
+
+ return 0;
+}
+
+static int nft_setelem_deactivate(const struct net *net,
+ struct nft_set *set,
+ struct nft_set_elem *elem, u32 flags)
+{
+ int ret;
+
+ if (flags & NFT_SET_ELEM_CATCHALL)
+ ret = nft_setelem_catchall_deactivate(net, set, elem);
+ else
+ ret = __nft_setelem_deactivate(net, set, elem);
+
+ return ret;
+}
+
+static void nft_setelem_catchall_remove(const struct net *net,
+ const struct nft_set *set,
+ const struct nft_set_elem *elem)
+{
+ struct nft_set_elem_catchall *catchall, *next;
+
+ list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
+ if (catchall->elem == elem->priv) {
+ list_del_rcu(&catchall->list);
+ kfree_rcu(catchall);
+ break;
+ }
+ }
+}
+
+static void nft_setelem_remove(const struct net *net,
+ const struct nft_set *set,
+ const struct nft_set_elem *elem)
+{
+ if (nft_setelem_is_catchall(set, elem))
+ nft_setelem_catchall_remove(net, set, elem);
+ else
+ set->ops->remove(net, set, elem);
+}
+
static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr, u32 nlmsg_flags)
{
@@ -5361,14 +5668,15 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (err < 0)
return err;
- if (nla[NFTA_SET_ELEM_KEY] == NULL)
- return -EINVAL;
-
nft_set_ext_prepare(&tmpl);
err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags);
if (err < 0)
return err;
+
+ if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
+ return -EINVAL;
+
if (flags != 0)
nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
@@ -5473,12 +5781,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
num_exprs = set->num_exprs;
}
- err = nft_setelem_parse_key(ctx, set, &elem.key.val,
- nla[NFTA_SET_ELEM_KEY]);
- if (err < 0)
- goto err_set_elem_expr;
+ if (nla[NFTA_SET_ELEM_KEY]) {
+ err = nft_setelem_parse_key(ctx, set, &elem.key.val,
+ nla[NFTA_SET_ELEM_KEY]);
+ if (err < 0)
+ goto err_set_elem_expr;
- nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+ nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+ }
if (nla[NFTA_SET_ELEM_KEY_END]) {
err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
@@ -5595,7 +5905,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
}
ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK;
- err = set->ops->insert(ctx->net, set, &elem, &ext2);
+
+ err = nft_setelem_insert(ctx->net, set, &elem, &ext2, flags);
if (err) {
if (err == -EEXIST) {
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) ^
@@ -5622,7 +5933,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
goto err_element_clash;
}
- if (set->size &&
+ if (!(flags & NFT_SET_ELEM_CATCHALL) && set->size &&
!atomic_add_unless(&set->nelems, 1, set->size + set->ndeact)) {
err = -ENFILE;
goto err_set_full;
@@ -5633,7 +5944,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
return 0;
err_set_full:
- set->ops->remove(ctx->net, set, &elem);
+ nft_setelem_remove(ctx->net, set, &elem);
err_element_clash:
kfree(trans);
err_elem_expr:
@@ -5655,13 +5966,14 @@ err_set_elem_expr_clone:
return err;
}
-static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_newsetelem(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
- u8 genmask = nft_genmask_next(net);
+ struct nftables_pernet *nft_net = nft_pernet(info->net);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_next(info->net);
+ struct net *net = info->net;
const struct nlattr *attr;
struct nft_set *set;
struct nft_ctx ctx;
@@ -5670,7 +5982,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
return -EINVAL;
- err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, extack,
+ err = nft_ctx_init_from_elemattr(&ctx, net, skb, info->nlh, nla, extack,
genmask, NETLINK_CB(skb).portid);
if (err < 0)
return err;
@@ -5684,7 +5996,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
return -EBUSY;
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
- err = nft_add_set_elem(&ctx, set, attr, nlh->nlmsg_flags);
+ err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags);
if (err < 0)
return err;
}
@@ -5731,9 +6043,9 @@ void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
}
}
-static void nft_set_elem_activate(const struct net *net,
- const struct nft_set *set,
- struct nft_set_elem *elem)
+static void nft_setelem_data_activate(const struct net *net,
+ const struct nft_set *set,
+ struct nft_set_elem *elem)
{
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
@@ -5743,9 +6055,9 @@ static void nft_set_elem_activate(const struct net *net,
(*nft_set_ext_obj(ext))->use++;
}
-static void nft_set_elem_deactivate(const struct net *net,
- const struct nft_set *set,
- struct nft_set_elem *elem)
+static void nft_setelem_data_deactivate(const struct net *net,
+ const struct nft_set *set,
+ struct nft_set_elem *elem)
{
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
@@ -5764,7 +6076,6 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_ext *ext;
struct nft_trans *trans;
u32 flags = 0;
- void *priv;
int err;
err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr,
@@ -5772,23 +6083,26 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
if (err < 0)
return err;
- if (nla[NFTA_SET_ELEM_KEY] == NULL)
+ err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags);
+ if (err < 0)
+ return err;
+
+ if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
return -EINVAL;
nft_set_ext_prepare(&tmpl);
- err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags);
- if (err < 0)
- return err;
if (flags != 0)
nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
- err = nft_setelem_parse_key(ctx, set, &elem.key.val,
- nla[NFTA_SET_ELEM_KEY]);
- if (err < 0)
- return err;
+ if (nla[NFTA_SET_ELEM_KEY]) {
+ err = nft_setelem_parse_key(ctx, set, &elem.key.val,
+ nla[NFTA_SET_ELEM_KEY]);
+ if (err < 0)
+ return err;
- nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+ nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+ }
if (nla[NFTA_SET_ELEM_KEY_END]) {
err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
@@ -5814,15 +6128,11 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
if (trans == NULL)
goto fail_trans;
- priv = set->ops->deactivate(ctx->net, set, &elem);
- if (priv == NULL) {
- err = -ENOENT;
+ err = nft_setelem_deactivate(ctx->net, set, &elem, flags);
+ if (err < 0)
goto fail_ops;
- }
- kfree(elem.priv);
- elem.priv = priv;
- nft_set_elem_deactivate(ctx->net, set, &elem);
+ nft_setelem_data_deactivate(ctx->net, set, &elem);
nft_trans_elem(trans) = elem;
nft_trans_commit_list_add_tail(ctx->net, trans);
@@ -5837,10 +6147,10 @@ fail_elem:
return err;
}
-static int nft_flush_set(const struct nft_ctx *ctx,
- struct nft_set *set,
- const struct nft_set_iter *iter,
- struct nft_set_elem *elem)
+static int nft_setelem_flush(const struct nft_ctx *ctx,
+ struct nft_set *set,
+ const struct nft_set_iter *iter,
+ struct nft_set_elem *elem)
{
struct nft_trans *trans;
int err;
@@ -5856,7 +6166,7 @@ static int nft_flush_set(const struct nft_ctx *ctx,
}
set->ndeact++;
- nft_set_elem_deactivate(ctx->net, set, elem);
+ nft_setelem_data_deactivate(ctx->net, set, elem);
nft_trans_elem_set(trans) = set;
nft_trans_elem(trans) = *elem;
nft_trans_commit_list_add_tail(ctx->net, trans);
@@ -5867,18 +6177,76 @@ err1:
return err;
}
-static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int __nft_set_catchall_flush(const struct nft_ctx *ctx,
+ struct nft_set *set,
+ struct nft_set_elem *elem)
{
- u8 genmask = nft_genmask_next(net);
+ struct nft_trans *trans;
+
+ trans = nft_trans_alloc_gfp(ctx, NFT_MSG_DELSETELEM,
+ sizeof(struct nft_trans_elem), GFP_KERNEL);
+ if (!trans)
+ return -ENOMEM;
+
+ nft_setelem_data_deactivate(ctx->net, set, elem);
+ nft_trans_elem_set(trans) = set;
+ nft_trans_elem(trans) = *elem;
+ nft_trans_commit_list_add_tail(ctx->net, trans);
+
+ return 0;
+}
+
+static int nft_set_catchall_flush(const struct nft_ctx *ctx,
+ struct nft_set *set)
+{
+ u8 genmask = nft_genmask_next(ctx->net);
+ struct nft_set_elem_catchall *catchall;
+ struct nft_set_elem elem;
+ struct nft_set_ext *ext;
+ int ret = 0;
+
+ list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+ ext = nft_set_elem_ext(set, catchall->elem);
+ if (!nft_set_elem_active(ext, genmask) ||
+ nft_set_elem_mark_busy(ext))
+ continue;
+
+ elem.priv = catchall->elem;
+ ret = __nft_set_catchall_flush(ctx, set, &elem);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static int nft_set_flush(struct nft_ctx *ctx, struct nft_set *set, u8 genmask)
+{
+ struct nft_set_iter iter = {
+ .genmask = genmask,
+ .fn = nft_setelem_flush,
+ };
+
+ set->ops->walk(ctx, set, &iter);
+ if (!iter.err)
+ iter.err = nft_set_catchall_flush(ctx, set);
+
+ return iter.err;
+}
+
+static int nf_tables_delsetelem(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const nla[])
+{
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_next(info->net);
+ struct net *net = info->net;
const struct nlattr *attr;
struct nft_set *set;
struct nft_ctx ctx;
int rem, err = 0;
- err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, extack,
+ err = nft_ctx_init_from_elemattr(&ctx, net, skb, info->nlh, nla, extack,
genmask, NETLINK_CB(skb).portid);
if (err < 0)
return err;
@@ -5889,22 +6257,13 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
return -EBUSY;
- if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) {
- struct nft_set_iter iter = {
- .genmask = genmask,
- .fn = nft_flush_set,
- };
- set->ops->walk(&ctx, set, &iter);
-
- return iter.err;
- }
+ if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS])
+ return nft_set_flush(&ctx, set, genmask);
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
err = nft_del_setelem(&ctx, set, attr);
if (err < 0)
break;
-
- set->ndeact++;
}
return err;
}
@@ -6162,15 +6521,15 @@ err_free_trans:
return err;
}
-static int nf_tables_newobj(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_next(info->net);
const struct nft_object_type *type;
- u8 genmask = nft_genmask_next(net);
int family = nfmsg->nfgen_family;
+ struct net *net = info->net;
struct nft_table *table;
struct nft_object *obj;
struct nft_ctx ctx;
@@ -6198,20 +6557,20 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
return err;
}
} else {
- if (nlh->nlmsg_flags & NLM_F_EXCL) {
+ if (info->nlh->nlmsg_flags & NLM_F_EXCL) {
NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_NAME]);
return -EEXIST;
}
- if (nlh->nlmsg_flags & NLM_F_REPLACE)
+ if (info->nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP;
type = __nft_obj_type_get(objtype);
- nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
return nf_tables_updobj(&ctx, type, nla[NFTA_OBJ_DATA], obj);
}
- nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
type = nft_obj_type_get(net, objtype);
if (IS_ERR(type))
@@ -6323,7 +6682,7 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
reset = true;
rcu_read_lock();
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
list_for_each_entry_rcu(table, &nft_net->tables, list) {
@@ -6418,22 +6777,22 @@ static int nf_tables_dump_obj_done(struct netlink_callback *cb)
}
/* called with rcu_read_lock held */
-static int nf_tables_getobj(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_getobj(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_cur(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_cur(info->net);
int family = nfmsg->nfgen_family;
const struct nft_table *table;
+ struct net *net = info->net;
struct nft_object *obj;
struct sk_buff *skb2;
bool reset = false;
u32 objtype;
int err;
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.start = nf_tables_dump_obj_start,
.dump = nf_tables_dump_obj,
@@ -6442,7 +6801,7 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
.data = (void *)nla,
};
- return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c);
+ return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
}
if (!nla[NFTA_OBJ_NAME] ||
@@ -6466,14 +6825,14 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
if (!skb2)
return -ENOMEM;
- if (NFNL_MSG_TYPE(nlh->nlmsg_type) == NFT_MSG_GETOBJ_RESET)
+ if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETOBJ_RESET)
reset = true;
if (reset) {
const struct nftables_pernet *nft_net;
char *buf;
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
buf = kasprintf(GFP_ATOMIC, "%s:%u", table->name, nft_net->base_seq);
audit_log_nfcfg(buf,
@@ -6485,7 +6844,7 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
}
err = nf_tables_fill_obj_info(skb2, net, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq, NFT_MSG_NEWOBJ, 0,
+ info->nlh->nlmsg_seq, NFT_MSG_NEWOBJ, 0,
family, table, obj, reset);
if (err < 0)
goto err_fill_obj_info;
@@ -6508,14 +6867,14 @@ static void nft_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj)
kfree(obj);
}
-static int nf_tables_delobj(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_delobj(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_next(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_next(info->net);
int family = nfmsg->nfgen_family;
+ struct net *net = info->net;
const struct nlattr *attr;
struct nft_table *table;
struct nft_object *obj;
@@ -6551,7 +6910,7 @@ static int nf_tables_delobj(struct net *net, struct sock *nlsk,
return -EBUSY;
}
- nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
return nft_delobj(&ctx, obj);
}
@@ -6560,7 +6919,7 @@ void nft_obj_notify(struct net *net, const struct nft_table *table,
struct nft_object *obj, u32 portid, u32 seq, int event,
int family, int report, gfp_t gfp)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct sk_buff *skb;
int err;
char *buf = kasprintf(gfp, "%s:%u",
@@ -6938,19 +7297,19 @@ err_flowtable_update_hook:
}
-static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_newflowtable(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
struct nft_flowtable_hook flowtable_hook;
+ u8 genmask = nft_genmask_next(info->net);
const struct nf_flowtable_type *type;
- u8 genmask = nft_genmask_next(net);
int family = nfmsg->nfgen_family;
struct nft_flowtable *flowtable;
struct nft_hook *hook, *next;
+ struct net *net = info->net;
struct nft_table *table;
struct nft_ctx ctx;
int err;
@@ -6976,17 +7335,17 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
return err;
}
} else {
- if (nlh->nlmsg_flags & NLM_F_EXCL) {
+ if (info->nlh->nlmsg_flags & NLM_F_EXCL) {
NL_SET_BAD_ATTR(extack, nla[NFTA_FLOWTABLE_NAME]);
return -EEXIST;
}
- nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
- return nft_flowtable_update(&ctx, nlh, flowtable);
+ return nft_flowtable_update(&ctx, info->nlh, flowtable);
}
- nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
flowtable = kzalloc(sizeof(*flowtable), GFP_KERNEL);
if (!flowtable)
@@ -7127,16 +7486,16 @@ err_flowtable_del_hook:
return err;
}
-static int nf_tables_delflowtable(struct net *net, struct sock *nlsk,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_delflowtable(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_next(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ struct netlink_ext_ack *extack = info->extack;
+ u8 genmask = nft_genmask_next(info->net);
int family = nfmsg->nfgen_family;
struct nft_flowtable *flowtable;
+ struct net *net = info->net;
const struct nlattr *attr;
struct nft_table *table;
struct nft_ctx ctx;
@@ -7166,7 +7525,7 @@ static int nf_tables_delflowtable(struct net *net, struct sock *nlsk,
return PTR_ERR(flowtable);
}
- nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
if (nla[NFTA_FLOWTABLE_HOOK])
return nft_delflowtable_hook(&ctx, flowtable);
@@ -7246,7 +7605,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb,
const struct nft_table *table;
rcu_read_lock();
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
cb->seq = nft_net->base_seq;
list_for_each_entry_rcu(table, &nft_net->tables, list) {
@@ -7322,21 +7681,20 @@ static int nf_tables_dump_flowtable_done(struct netlink_callback *cb)
}
/* called with rcu_read_lock held */
-static int nf_tables_getflowtable(struct net *net, struct sock *nlsk,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_getflowtable(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- u8 genmask = nft_genmask_cur(net);
+ const struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ u8 genmask = nft_genmask_cur(info->net);
int family = nfmsg->nfgen_family;
struct nft_flowtable *flowtable;
const struct nft_table *table;
+ struct net *net = info->net;
struct sk_buff *skb2;
int err;
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.start = nf_tables_dump_flowtable_start,
.dump = nf_tables_dump_flowtable,
@@ -7345,7 +7703,7 @@ static int nf_tables_getflowtable(struct net *net, struct sock *nlsk,
.data = (void *)nla,
};
- return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c);
+ return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
}
if (!nla[NFTA_FLOWTABLE_NAME])
@@ -7366,7 +7724,7 @@ static int nf_tables_getflowtable(struct net *net, struct sock *nlsk,
return -ENOMEM;
err = nf_tables_fill_flowtable_info(skb2, net, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq,
+ info->nlh->nlmsg_seq,
NFT_MSG_NEWFLOWTABLE, 0, family,
flowtable, &flowtable->hook_list);
if (err < 0)
@@ -7384,7 +7742,7 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
struct list_head *hook_list,
int event)
{
- struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct sk_buff *skb;
int err;
@@ -7429,7 +7787,7 @@ static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable)
static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
u32 portid, u32 seq)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nlmsghdr *nlh;
char buf[TASK_COMM_LEN];
int event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWGEN);
@@ -7482,7 +7840,7 @@ static int nf_tables_flowtable_event(struct notifier_block *this,
return 0;
net = dev_net(dev);
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex);
list_for_each_entry(table, &nft_net->tables, list) {
list_for_each_entry(flowtable, &table->flowtables, list) {
@@ -7528,10 +7886,8 @@ err:
-ENOBUFS);
}
-static int nf_tables_getgen(struct net *net, struct sock *nlsk,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct netlink_ext_ack *extack)
+static int nf_tables_getgen(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nla[])
{
struct sk_buff *skb2;
int err;
@@ -7540,12 +7896,12 @@ static int nf_tables_getgen(struct net *net, struct sock *nlsk,
if (skb2 == NULL)
return -ENOMEM;
- err = nf_tables_fill_gen_info(skb2, net, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq);
+ err = nf_tables_fill_gen_info(skb2, info->net, NETLINK_CB(skb).portid,
+ info->nlh->nlmsg_seq);
if (err < 0)
goto err_fill_gen_info;
- return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
+ return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
err_fill_gen_info:
kfree_skb(skb2);
@@ -7554,115 +7910,138 @@ err_fill_gen_info:
static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
[NFT_MSG_NEWTABLE] = {
- .call_batch = nf_tables_newtable,
+ .call = nf_tables_newtable,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_TABLE_MAX,
.policy = nft_table_policy,
},
[NFT_MSG_GETTABLE] = {
- .call_rcu = nf_tables_gettable,
+ .call = nf_tables_gettable,
+ .type = NFNL_CB_RCU,
.attr_count = NFTA_TABLE_MAX,
.policy = nft_table_policy,
},
[NFT_MSG_DELTABLE] = {
- .call_batch = nf_tables_deltable,
+ .call = nf_tables_deltable,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_TABLE_MAX,
.policy = nft_table_policy,
},
[NFT_MSG_NEWCHAIN] = {
- .call_batch = nf_tables_newchain,
+ .call = nf_tables_newchain,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_CHAIN_MAX,
.policy = nft_chain_policy,
},
[NFT_MSG_GETCHAIN] = {
- .call_rcu = nf_tables_getchain,
+ .call = nf_tables_getchain,
+ .type = NFNL_CB_RCU,
.attr_count = NFTA_CHAIN_MAX,
.policy = nft_chain_policy,
},
[NFT_MSG_DELCHAIN] = {
- .call_batch = nf_tables_delchain,
+ .call = nf_tables_delchain,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_CHAIN_MAX,
.policy = nft_chain_policy,
},
[NFT_MSG_NEWRULE] = {
- .call_batch = nf_tables_newrule,
+ .call = nf_tables_newrule,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_RULE_MAX,
.policy = nft_rule_policy,
},
[NFT_MSG_GETRULE] = {
- .call_rcu = nf_tables_getrule,
+ .call = nf_tables_getrule,
+ .type = NFNL_CB_RCU,
.attr_count = NFTA_RULE_MAX,
.policy = nft_rule_policy,
},
[NFT_MSG_DELRULE] = {
- .call_batch = nf_tables_delrule,
+ .call = nf_tables_delrule,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_RULE_MAX,
.policy = nft_rule_policy,
},
[NFT_MSG_NEWSET] = {
- .call_batch = nf_tables_newset,
+ .call = nf_tables_newset,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_SET_MAX,
.policy = nft_set_policy,
},
[NFT_MSG_GETSET] = {
- .call_rcu = nf_tables_getset,
+ .call = nf_tables_getset,
+ .type = NFNL_CB_RCU,
.attr_count = NFTA_SET_MAX,
.policy = nft_set_policy,
},
[NFT_MSG_DELSET] = {
- .call_batch = nf_tables_delset,
+ .call = nf_tables_delset,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_SET_MAX,
.policy = nft_set_policy,
},
[NFT_MSG_NEWSETELEM] = {
- .call_batch = nf_tables_newsetelem,
+ .call = nf_tables_newsetelem,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_SET_ELEM_LIST_MAX,
.policy = nft_set_elem_list_policy,
},
[NFT_MSG_GETSETELEM] = {
- .call_rcu = nf_tables_getsetelem,
+ .call = nf_tables_getsetelem,
+ .type = NFNL_CB_RCU,
.attr_count = NFTA_SET_ELEM_LIST_MAX,
.policy = nft_set_elem_list_policy,
},
[NFT_MSG_DELSETELEM] = {
- .call_batch = nf_tables_delsetelem,
+ .call = nf_tables_delsetelem,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_SET_ELEM_LIST_MAX,
.policy = nft_set_elem_list_policy,
},
[NFT_MSG_GETGEN] = {
- .call_rcu = nf_tables_getgen,
+ .call = nf_tables_getgen,
+ .type = NFNL_CB_RCU,
},
[NFT_MSG_NEWOBJ] = {
- .call_batch = nf_tables_newobj,
+ .call = nf_tables_newobj,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_OBJ_MAX,
.policy = nft_obj_policy,
},
[NFT_MSG_GETOBJ] = {
- .call_rcu = nf_tables_getobj,
+ .call = nf_tables_getobj,
+ .type = NFNL_CB_RCU,
.attr_count = NFTA_OBJ_MAX,
.policy = nft_obj_policy,
},
[NFT_MSG_DELOBJ] = {
- .call_batch = nf_tables_delobj,
+ .call = nf_tables_delobj,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_OBJ_MAX,
.policy = nft_obj_policy,
},
[NFT_MSG_GETOBJ_RESET] = {
- .call_rcu = nf_tables_getobj,
+ .call = nf_tables_getobj,
+ .type = NFNL_CB_RCU,
.attr_count = NFTA_OBJ_MAX,
.policy = nft_obj_policy,
},
[NFT_MSG_NEWFLOWTABLE] = {
- .call_batch = nf_tables_newflowtable,
+ .call = nf_tables_newflowtable,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_FLOWTABLE_MAX,
.policy = nft_flowtable_policy,
},
[NFT_MSG_GETFLOWTABLE] = {
- .call_rcu = nf_tables_getflowtable,
+ .call = nf_tables_getflowtable,
+ .type = NFNL_CB_RCU,
.attr_count = NFTA_FLOWTABLE_MAX,
.policy = nft_flowtable_policy,
},
[NFT_MSG_DELFLOWTABLE] = {
- .call_batch = nf_tables_delflowtable,
+ .call = nf_tables_delflowtable,
+ .type = NFNL_CB_BATCH,
.attr_count = NFTA_FLOWTABLE_MAX,
.policy = nft_flowtable_policy,
},
@@ -7670,7 +8049,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
static int nf_tables_validate(struct net *net)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_table *table;
switch (nft_net->validate_state) {
@@ -7855,7 +8234,7 @@ static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *cha
static void nf_tables_commit_chain_prepare_cancel(struct net *net)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_trans *trans, *next;
list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) {
@@ -7967,7 +8346,7 @@ static void nft_flowtable_hooks_del(struct nft_flowtable *flowtable,
static void nf_tables_module_autoload_cleanup(struct net *net)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_module_request *req, *next;
WARN_ON_ONCE(!list_empty(&nft_net->commit_list));
@@ -7980,7 +8359,7 @@ static void nf_tables_module_autoload_cleanup(struct net *net)
static void nf_tables_commit_release(struct net *net)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_trans *trans;
/* all side effects have to be made visible.
@@ -8014,7 +8393,7 @@ static void nf_tables_commit_release(struct net *net)
static void nft_commit_notify(struct net *net, u32 portid)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct sk_buff *batch_skb = NULL, *nskb, *skb;
unsigned char *data;
int len;
@@ -8101,7 +8480,7 @@ static void nf_tables_commit_audit_log(struct list_head *adl, u32 generation)
static int nf_tables_commit(struct net *net, struct sk_buff *skb)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_trans *trans, *next;
struct nft_trans_elem *te;
struct nft_chain *chain;
@@ -8235,7 +8614,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
case NFT_MSG_NEWSETELEM:
te = (struct nft_trans_elem *)trans->data;
- te->set->ops->activate(net, te->set, &te->elem);
+ nft_setelem_activate(net, te->set, &te->elem);
nf_tables_setelem_notify(&trans->ctx, te->set,
&te->elem,
NFT_MSG_NEWSETELEM, 0);
@@ -8247,9 +8626,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nf_tables_setelem_notify(&trans->ctx, te->set,
&te->elem,
NFT_MSG_DELSETELEM, 0);
- te->set->ops->remove(net, te->set, &te->elem);
- atomic_dec(&te->set->nelems);
- te->set->ndeact--;
+ nft_setelem_remove(net, te->set, &te->elem);
+ if (!nft_setelem_is_catchall(te->set, &te->elem)) {
+ atomic_dec(&te->set->nelems);
+ te->set->ndeact--;
+ }
break;
case NFT_MSG_NEWOBJ:
if (nft_trans_obj_update(trans)) {
@@ -8322,7 +8703,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
static void nf_tables_module_autoload(struct net *net)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_module_request *req, *next;
LIST_HEAD(module_list);
@@ -8370,7 +8751,7 @@ static void nf_tables_abort_release(struct nft_trans *trans)
static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_trans *trans, *next;
struct nft_trans_elem *te;
struct nft_hook *hook;
@@ -8450,15 +8831,17 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
break;
}
te = (struct nft_trans_elem *)trans->data;
- te->set->ops->remove(net, te->set, &te->elem);
- atomic_dec(&te->set->nelems);
+ nft_setelem_remove(net, te->set, &te->elem);
+ if (!nft_setelem_is_catchall(te->set, &te->elem))
+ atomic_dec(&te->set->nelems);
break;
case NFT_MSG_DELSETELEM:
te = (struct nft_trans_elem *)trans->data;
- nft_set_elem_activate(net, te->set, &te->elem);
- te->set->ops->activate(net, te->set, &te->elem);
- te->set->ndeact--;
+ nft_setelem_data_activate(net, te->set, &te->elem);
+ nft_setelem_activate(net, te->set, &te->elem);
+ if (!nft_setelem_is_catchall(te->set, &te->elem))
+ te->set->ndeact--;
nft_trans_destroy(trans);
break;
@@ -8524,7 +8907,7 @@ static void nf_tables_cleanup(struct net *net)
static int nf_tables_abort(struct net *net, struct sk_buff *skb,
enum nfnl_abort_action action)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
int ret = __nf_tables_abort(net, action);
mutex_unlock(&nft_net->commit_mutex);
@@ -8534,7 +8917,7 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb,
static bool nf_tables_valid_genid(struct net *net, u32 genid)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
bool genid_ok;
mutex_lock(&nft_net->commit_mutex);
@@ -8603,26 +8986,59 @@ EXPORT_SYMBOL_GPL(nft_chain_validate_hooks);
static int nf_tables_check_loops(const struct nft_ctx *ctx,
const struct nft_chain *chain);
+static int nft_check_loops(const struct nft_ctx *ctx,
+ const struct nft_set_ext *ext)
+{
+ const struct nft_data *data;
+ int ret;
+
+ data = nft_set_ext_data(ext);
+ switch (data->verdict.code) {
+ case NFT_JUMP:
+ case NFT_GOTO:
+ ret = nf_tables_check_loops(ctx, data->verdict.chain);
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
struct nft_set *set,
const struct nft_set_iter *iter,
struct nft_set_elem *elem)
{
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
- const struct nft_data *data;
if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
*nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
return 0;
- data = nft_set_ext_data(ext);
- switch (data->verdict.code) {
- case NFT_JUMP:
- case NFT_GOTO:
- return nf_tables_check_loops(ctx, data->verdict.chain);
- default:
- return 0;
+ return nft_check_loops(ctx, ext);
+}
+
+static int nft_set_catchall_loops(const struct nft_ctx *ctx,
+ struct nft_set *set)
+{
+ u8 genmask = nft_genmask_next(ctx->net);
+ struct nft_set_elem_catchall *catchall;
+ struct nft_set_ext *ext;
+ int ret = 0;
+
+ list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+ ext = nft_set_elem_ext(set, catchall->elem);
+ if (!nft_set_elem_active(ext, genmask))
+ continue;
+
+ ret = nft_check_loops(ctx, ext);
+ if (ret < 0)
+ return ret;
}
+
+ return ret;
}
static int nf_tables_check_loops(const struct nft_ctx *ctx,
@@ -8684,6 +9100,9 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
iter.fn = nf_tables_loop_check_setelem;
set->ops->walk(ctx, set, &iter);
+ if (!iter.err)
+ iter.err = nft_set_catchall_loops(ctx, set);
+
if (iter.err < 0)
return iter.err;
}
@@ -9096,7 +9515,7 @@ static void __nft_release_hook(struct net *net, struct nft_table *table)
static void __nft_release_hooks(struct net *net)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_table *table;
list_for_each_entry(table, &nft_net->tables, list) {
@@ -9156,7 +9575,7 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
static void __nft_release_tables(struct net *net)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_table *table, *nt;
list_for_each_entry_safe(table, nt, &nft_net->tables, list) {
@@ -9179,7 +9598,7 @@ static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
if (event != NETLINK_URELEASE || n->protocol != NETLINK_NETFILTER)
return NOTIFY_DONE;
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex);
list_for_each_entry(table, &nft_net->tables, list) {
if (nft_table_has_owner(table) &&
@@ -9207,7 +9626,7 @@ static struct notifier_block nft_nl_notifier = {
static int __net_init nf_tables_init_net(struct net *net)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
INIT_LIST_HEAD(&nft_net->tables);
INIT_LIST_HEAD(&nft_net->commit_list);
@@ -9227,7 +9646,7 @@ static void __net_exit nf_tables_pre_exit_net(struct net *net)
static void __net_exit nf_tables_exit_net(struct net *net)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex);
if (!list_empty(&nft_net->commit_list))
diff --git a/net/netfilter/nf_tables_offload.c b/net/netfilter/nf_tables_offload.c
index 19215e81dd66..a48c5fd53a80 100644
--- a/net/netfilter/nf_tables_offload.c
+++ b/net/netfilter/nf_tables_offload.c
@@ -7,8 +7,6 @@
#include <net/netfilter/nf_tables_offload.h>
#include <net/pkt_cls.h>
-extern unsigned int nf_tables_net_id;
-
static struct nft_flow_rule *nft_flow_rule_alloc(int num_actions)
{
struct nft_flow_rule *flow;
@@ -389,7 +387,7 @@ static void nft_indr_block_cleanup(struct flow_block_cb *block_cb)
nft_flow_block_offload_init(&bo, dev_net(dev), FLOW_BLOCK_UNBIND,
basechain, &extack);
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex);
list_del(&block_cb->driver_list);
list_move(&block_cb->list, &bo.cb_list);
@@ -490,7 +488,7 @@ static int nft_flow_offload_chain(struct nft_chain *chain, u8 *ppolicy,
static void nft_flow_rule_offload_abort(struct net *net,
struct nft_trans *trans)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
int err = 0;
list_for_each_entry_continue_reverse(trans, &nft_net->commit_list, list) {
@@ -539,7 +537,7 @@ static void nft_flow_rule_offload_abort(struct net *net,
int nft_flow_rule_offload_commit(struct net *net)
{
- struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_trans *trans;
int err = 0;
u8 policy;
@@ -663,7 +661,7 @@ static int nft_offload_netdev_event(struct notifier_block *this,
if (event != NETDEV_UNREGISTER)
return NOTIFY_DONE;
- nft_net = net_generic(net, nf_tables_net_id);
+ nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex);
chain = __nft_offload_get_chain(nft_net, dev);
if (chain)
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 06f5886f652e..d7a9628b6cee 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -252,6 +252,12 @@ replay:
struct nlattr *attr = (void *)nlh + min_len;
int attrlen = nlh->nlmsg_len - min_len;
__u8 subsys_id = NFNL_SUBSYS_ID(type);
+ struct nfnl_info info = {
+ .net = net,
+ .sk = nfnlnet->nfnl,
+ .nlh = nlh,
+ .extack = extack,
+ };
/* Sanity-check NFNL_MAX_ATTR_COUNT */
if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
@@ -267,24 +273,30 @@ replay:
return err;
}
- if (nc->call_rcu) {
- err = nc->call_rcu(net, nfnlnet->nfnl, skb, nlh,
- (const struct nlattr **)cda,
- extack);
+ if (!nc->call) {
rcu_read_unlock();
- } else {
+ return -EINVAL;
+ }
+
+ switch (nc->type) {
+ case NFNL_CB_RCU:
+ err = nc->call(skb, &info, (const struct nlattr **)cda);
+ rcu_read_unlock();
+ break;
+ case NFNL_CB_MUTEX:
rcu_read_unlock();
nfnl_lock(subsys_id);
if (nfnl_dereference_protected(subsys_id) != ss ||
- nfnetlink_find_client(type, ss) != nc)
+ nfnetlink_find_client(type, ss) != nc) {
err = -EAGAIN;
- else if (nc->call)
- err = nc->call(net, nfnlnet->nfnl, skb, nlh,
- (const struct nlattr **)cda,
- extack);
- else
- err = -EINVAL;
+ break;
+ }
+ err = nc->call(skb, &info, (const struct nlattr **)cda);
nfnl_unlock(subsys_id);
+ break;
+ default:
+ err = -EINVAL;
+ break;
}
if (err == -EAGAIN)
goto replay;
@@ -462,12 +474,24 @@ replay_abort:
goto ack;
}
+ if (nc->type != NFNL_CB_BATCH) {
+ err = -EINVAL;
+ goto ack;
+ }
+
{
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
- u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
+ struct nfnl_net *nfnlnet = nfnl_pernet(net);
struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1];
struct nlattr *attr = (void *)nlh + min_len;
+ u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
int attrlen = nlh->nlmsg_len - min_len;
+ struct nfnl_info info = {
+ .net = net,
+ .sk = nfnlnet->nfnl,
+ .nlh = nlh,
+ .extack = &extack,
+ };
/* Sanity-check NFTA_MAX_ATTR */
if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
@@ -482,13 +506,7 @@ replay_abort:
if (err < 0)
goto ack;
- if (nc->call_batch) {
- struct nfnl_net *nfnlnet = nfnl_pernet(net);
-
- err = nc->call_batch(net, nfnlnet->nfnl, skb, nlh,
- (const struct nlattr **)cda,
- &extack);
- }
+ err = nc->call(skb, &info, (const struct nlattr **)cda);
/* The lock was released to autoload some module, we
* have to abort and start from scratch using the
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c
index 6895f31c5fbb..3c8cf8748cfb 100644
--- a/net/netfilter/nfnetlink_acct.c
+++ b/net/netfilter/nfnetlink_acct.c
@@ -56,15 +56,13 @@ static inline struct nfnl_acct_net *nfnl_acct_pernet(struct net *net)
#define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
#define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */
-static int nfnl_acct_new(struct net *net, struct sock *nfnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const tb[],
- struct netlink_ext_ack *extack)
+static int nfnl_acct_new(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const tb[])
{
- struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net);
+ struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
struct nf_acct *nfacct, *matching = NULL;
- char *acct_name;
unsigned int size = 0;
+ char *acct_name;
u32 flags = 0;
if (!tb[NFACCT_NAME])
@@ -78,7 +76,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl,
if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0)
continue;
- if (nlh->nlmsg_flags & NLM_F_EXCL)
+ if (info->nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST;
matching = nfacct;
@@ -86,7 +84,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl,
}
if (matching) {
- if (nlh->nlmsg_flags & NLM_F_REPLACE) {
+ if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
/* reset counters if you request a replacement. */
atomic64_set(&matching->pkts, 0);
atomic64_set(&matching->bytes, 0);
@@ -273,17 +271,15 @@ static int nfnl_acct_start(struct netlink_callback *cb)
return 0;
}
-static int nfnl_acct_get(struct net *net, struct sock *nfnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const tb[],
- struct netlink_ext_ack *extack)
+static int nfnl_acct_get(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const tb[])
{
- struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net);
+ struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
int ret = -ENOENT;
struct nf_acct *cur;
char *acct_name;
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = nfnl_acct_dump,
.start = nfnl_acct_start,
@@ -291,7 +287,7 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl,
.data = (void *)tb[NFACCT_FILTER],
};
- return netlink_dump_start(nfnl, skb, nlh, &c);
+ return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
if (!tb[NFACCT_NAME])
@@ -311,15 +307,15 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl,
}
ret = nfnl_acct_fill_info(skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq,
- NFNL_MSG_TYPE(nlh->nlmsg_type),
- NFNL_MSG_ACCT_NEW, cur);
+ info->nlh->nlmsg_seq,
+ NFNL_MSG_TYPE(info->nlh->nlmsg_type),
+ NFNL_MSG_ACCT_NEW, cur);
if (ret <= 0) {
kfree_skb(skb2);
break;
}
- ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
- MSG_DONTWAIT);
+ ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (ret > 0)
ret = 0;
@@ -347,12 +343,10 @@ static int nfnl_acct_try_del(struct nf_acct *cur)
return ret;
}
-static int nfnl_acct_del(struct net *net, struct sock *nfnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const tb[],
- struct netlink_ext_ack *extack)
+static int nfnl_acct_del(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const tb[])
{
- struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net);
+ struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
struct nf_acct *cur, *tmp;
int ret = -ENOENT;
char *acct_name;
@@ -388,18 +382,30 @@ static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = {
};
static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = {
- [NFNL_MSG_ACCT_NEW] = { .call = nfnl_acct_new,
- .attr_count = NFACCT_MAX,
- .policy = nfnl_acct_policy },
- [NFNL_MSG_ACCT_GET] = { .call = nfnl_acct_get,
- .attr_count = NFACCT_MAX,
- .policy = nfnl_acct_policy },
- [NFNL_MSG_ACCT_GET_CTRZERO] = { .call = nfnl_acct_get,
- .attr_count = NFACCT_MAX,
- .policy = nfnl_acct_policy },
- [NFNL_MSG_ACCT_DEL] = { .call = nfnl_acct_del,
- .attr_count = NFACCT_MAX,
- .policy = nfnl_acct_policy },
+ [NFNL_MSG_ACCT_NEW] = {
+ .call = nfnl_acct_new,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = NFACCT_MAX,
+ .policy = nfnl_acct_policy
+ },
+ [NFNL_MSG_ACCT_GET] = {
+ .call = nfnl_acct_get,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = NFACCT_MAX,
+ .policy = nfnl_acct_policy
+ },
+ [NFNL_MSG_ACCT_GET_CTRZERO] = {
+ .call = nfnl_acct_get,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = NFACCT_MAX,
+ .policy = nfnl_acct_policy
+ },
+ [NFNL_MSG_ACCT_DEL] = {
+ .call = nfnl_acct_del,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = NFACCT_MAX,
+ .policy = nfnl_acct_policy
+ },
};
static const struct nfnetlink_subsystem nfnl_acct_subsys = {
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c
index 22f6f7fcc724..322ac5dd5402 100644
--- a/net/netfilter/nfnetlink_cthelper.c
+++ b/net/netfilter/nfnetlink_cthelper.c
@@ -408,10 +408,8 @@ nfnl_cthelper_update(const struct nlattr * const tb[],
return 0;
}
-static int nfnl_cthelper_new(struct net *net, struct sock *nfnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const tb[],
- struct netlink_ext_ack *extack)
+static int nfnl_cthelper_new(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const tb[])
{
const char *helper_name;
struct nf_conntrack_helper *cur, *helper = NULL;
@@ -441,7 +439,7 @@ static int nfnl_cthelper_new(struct net *net, struct sock *nfnl,
tuple.dst.protonum != cur->tuple.dst.protonum))
continue;
- if (nlh->nlmsg_flags & NLM_F_EXCL)
+ if (info->nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST;
helper = cur;
@@ -607,10 +605,8 @@ out:
return skb->len;
}
-static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const tb[],
- struct netlink_ext_ack *extack)
+static int nfnl_cthelper_get(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const tb[])
{
int ret = -ENOENT;
struct nf_conntrack_helper *cur;
@@ -623,11 +619,11 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = nfnl_cthelper_dump_table,
};
- return netlink_dump_start(nfnl, skb, nlh, &c);
+ return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
if (tb[NFCTH_NAME])
@@ -659,15 +655,15 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
}
ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq,
- NFNL_MSG_TYPE(nlh->nlmsg_type),
+ info->nlh->nlmsg_seq,
+ NFNL_MSG_TYPE(info->nlh->nlmsg_type),
NFNL_MSG_CTHELPER_NEW, cur);
if (ret <= 0) {
kfree_skb(skb2);
break;
}
- ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
+ ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT);
if (ret > 0)
ret = 0;
@@ -678,10 +674,8 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
return ret;
}
-static int nfnl_cthelper_del(struct net *net, struct sock *nfnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const tb[],
- struct netlink_ext_ack *extack)
+static int nfnl_cthelper_del(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const tb[])
{
char *helper_name = NULL;
struct nf_conntrack_helper *cur;
@@ -743,15 +737,24 @@ static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {
};
static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = {
- [NFNL_MSG_CTHELPER_NEW] = { .call = nfnl_cthelper_new,
- .attr_count = NFCTH_MAX,
- .policy = nfnl_cthelper_policy },
- [NFNL_MSG_CTHELPER_GET] = { .call = nfnl_cthelper_get,
- .attr_count = NFCTH_MAX,
- .policy = nfnl_cthelper_policy },
- [NFNL_MSG_CTHELPER_DEL] = { .call = nfnl_cthelper_del,
- .attr_count = NFCTH_MAX,
- .policy = nfnl_cthelper_policy },
+ [NFNL_MSG_CTHELPER_NEW] = {
+ .call = nfnl_cthelper_new,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = NFCTH_MAX,
+ .policy = nfnl_cthelper_policy
+ },
+ [NFNL_MSG_CTHELPER_GET] = {
+ .call = nfnl_cthelper_get,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = NFCTH_MAX,
+ .policy = nfnl_cthelper_policy
+ },
+ [NFNL_MSG_CTHELPER_DEL] = {
+ .call = nfnl_cthelper_del,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = NFCTH_MAX,
+ .policy = nfnl_cthelper_policy
+ },
};
static const struct nfnetlink_subsystem nfnl_cthelper_subsys = {
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c
index 46da5548d0b3..38848ad68899 100644
--- a/net/netfilter/nfnetlink_cttimeout.c
+++ b/net/netfilter/nfnetlink_cttimeout.c
@@ -83,13 +83,11 @@ err:
return ret;
}
-static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int cttimeout_new_timeout(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
- struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
+ struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
__u16 l3num;
__u8 l4num;
const struct nf_conntrack_l4proto *l4proto;
@@ -111,7 +109,7 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
continue;
- if (nlh->nlmsg_flags & NLM_F_EXCL)
+ if (info->nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST;
matching = timeout;
@@ -119,7 +117,7 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
}
if (matching) {
- if (nlh->nlmsg_flags & NLM_F_REPLACE) {
+ if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
/* You cannot replace one timeout policy by another of
* different kind, sorry.
*/
@@ -129,7 +127,8 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
return ctnl_timeout_parse_policy(&matching->timeout.data,
matching->timeout.l4proto,
- net, cda[CTA_TIMEOUT_DATA]);
+ info->net,
+ cda[CTA_TIMEOUT_DATA]);
}
return -EBUSY;
@@ -150,8 +149,8 @@ static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
goto err_proto_put;
}
- ret = ctnl_timeout_parse_policy(&timeout->timeout.data, l4proto, net,
- cda[CTA_TIMEOUT_DATA]);
+ ret = ctnl_timeout_parse_policy(&timeout->timeout.data, l4proto,
+ info->net, cda[CTA_TIMEOUT_DATA]);
if (ret < 0)
goto err;
@@ -248,22 +247,20 @@ ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
-static int cttimeout_get_timeout(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int cttimeout_get_timeout(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
- struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
+ struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
int ret = -ENOENT;
char *name;
struct ctnl_timeout *cur;
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.dump = ctnl_timeout_dump,
};
- return netlink_dump_start(ctnl, skb, nlh, &c);
+ return netlink_dump_start(info->sk, skb, info->nlh, &c);
}
if (!cda[CTA_TIMEOUT_NAME])
@@ -283,15 +280,15 @@ static int cttimeout_get_timeout(struct net *net, struct sock *ctnl,
}
ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq,
- NFNL_MSG_TYPE(nlh->nlmsg_type),
+ info->nlh->nlmsg_seq,
+ NFNL_MSG_TYPE(info->nlh->nlmsg_type),
IPCTNL_MSG_TIMEOUT_NEW, cur);
if (ret <= 0) {
kfree_skb(skb2);
break;
}
- ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid,
- MSG_DONTWAIT);
+ ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (ret > 0)
ret = 0;
@@ -320,13 +317,11 @@ static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout)
return ret;
}
-static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int cttimeout_del_timeout(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
- struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(net);
+ struct nfct_timeout_pernet *pernet = nfct_timeout_pernet(info->net);
struct ctnl_timeout *cur, *tmp;
int ret = -ENOENT;
char *name;
@@ -334,7 +329,7 @@ static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
if (!cda[CTA_TIMEOUT_NAME]) {
list_for_each_entry_safe(cur, tmp, &pernet->nfct_timeout_list,
head)
- ctnl_timeout_try_del(net, cur);
+ ctnl_timeout_try_del(info->net, cur);
return 0;
}
@@ -344,7 +339,7 @@ static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
continue;
- ret = ctnl_timeout_try_del(net, cur);
+ ret = ctnl_timeout_try_del(info->net, cur);
if (ret < 0)
return ret;
@@ -353,11 +348,9 @@ static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
return ret;
}
-static int cttimeout_default_set(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int cttimeout_default_set(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
const struct nf_conntrack_l4proto *l4proto;
__u8 l4num;
@@ -377,7 +370,7 @@ static int cttimeout_default_set(struct net *net, struct sock *ctnl,
goto err;
}
- ret = ctnl_timeout_parse_policy(NULL, l4proto, net,
+ ret = ctnl_timeout_parse_policy(NULL, l4proto, info->net,
cda[CTA_TIMEOUT_DATA]);
if (ret < 0)
goto err;
@@ -427,11 +420,9 @@ nla_put_failure:
return -1;
}
-static int cttimeout_default_get(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[],
- struct netlink_ext_ack *extack)
+static int cttimeout_default_get(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
const struct nf_conntrack_l4proto *l4proto;
unsigned int *timeouts = NULL;
@@ -453,35 +444,35 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
switch (l4proto->l4proto) {
case IPPROTO_ICMP:
- timeouts = &nf_icmp_pernet(net)->timeout;
+ timeouts = &nf_icmp_pernet(info->net)->timeout;
break;
case IPPROTO_TCP:
- timeouts = nf_tcp_pernet(net)->timeouts;
+ timeouts = nf_tcp_pernet(info->net)->timeouts;
break;
case IPPROTO_UDP:
case IPPROTO_UDPLITE:
- timeouts = nf_udp_pernet(net)->timeouts;
+ timeouts = nf_udp_pernet(info->net)->timeouts;
break;
case IPPROTO_DCCP:
#ifdef CONFIG_NF_CT_PROTO_DCCP
- timeouts = nf_dccp_pernet(net)->dccp_timeout;
+ timeouts = nf_dccp_pernet(info->net)->dccp_timeout;
#endif
break;
case IPPROTO_ICMPV6:
- timeouts = &nf_icmpv6_pernet(net)->timeout;
+ timeouts = &nf_icmpv6_pernet(info->net)->timeout;
break;
case IPPROTO_SCTP:
#ifdef CONFIG_NF_CT_PROTO_SCTP
- timeouts = nf_sctp_pernet(net)->timeouts;
+ timeouts = nf_sctp_pernet(info->net)->timeouts;
#endif
break;
case IPPROTO_GRE:
#ifdef CONFIG_NF_CT_PROTO_GRE
- timeouts = nf_gre_pernet(net)->timeouts;
+ timeouts = nf_gre_pernet(info->net)->timeouts;
#endif
break;
case 255:
- timeouts = &nf_generic_pernet(net)->timeout;
+ timeouts = &nf_generic_pernet(info->net)->timeout;
break;
default:
WARN_ONCE(1, "Missing timeouts for proto %d", l4proto->l4proto);
@@ -497,9 +488,10 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
goto err;
}
- ret = cttimeout_default_fill_info(net, skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq,
- NFNL_MSG_TYPE(nlh->nlmsg_type),
+ ret = cttimeout_default_fill_info(info->net, skb2,
+ NETLINK_CB(skb).portid,
+ info->nlh->nlmsg_seq,
+ NFNL_MSG_TYPE(info->nlh->nlmsg_type),
IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
l3num, l4proto, timeouts);
if (ret <= 0) {
@@ -507,7 +499,8 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
err = -ENOMEM;
goto err;
}
- ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
+ ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (ret > 0)
ret = 0;
@@ -553,21 +546,36 @@ static void ctnl_timeout_put(struct nf_ct_timeout *t)
}
static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = {
- [IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout,
- .attr_count = CTA_TIMEOUT_MAX,
- .policy = cttimeout_nla_policy },
- [IPCTNL_MSG_TIMEOUT_GET] = { .call = cttimeout_get_timeout,
- .attr_count = CTA_TIMEOUT_MAX,
- .policy = cttimeout_nla_policy },
- [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout,
- .attr_count = CTA_TIMEOUT_MAX,
- .policy = cttimeout_nla_policy },
- [IPCTNL_MSG_TIMEOUT_DEFAULT_SET]= { .call = cttimeout_default_set,
- .attr_count = CTA_TIMEOUT_MAX,
- .policy = cttimeout_nla_policy },
- [IPCTNL_MSG_TIMEOUT_DEFAULT_GET]= { .call = cttimeout_default_get,
- .attr_count = CTA_TIMEOUT_MAX,
- .policy = cttimeout_nla_policy },
+ [IPCTNL_MSG_TIMEOUT_NEW] = {
+ .call = cttimeout_new_timeout,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_TIMEOUT_MAX,
+ .policy = cttimeout_nla_policy
+ },
+ [IPCTNL_MSG_TIMEOUT_GET] = {
+ .call = cttimeout_get_timeout,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_TIMEOUT_MAX,
+ .policy = cttimeout_nla_policy
+ },
+ [IPCTNL_MSG_TIMEOUT_DELETE] = {
+ .call = cttimeout_del_timeout,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_TIMEOUT_MAX,
+ .policy = cttimeout_nla_policy
+ },
+ [IPCTNL_MSG_TIMEOUT_DEFAULT_SET] = {
+ .call = cttimeout_default_set,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_TIMEOUT_MAX,
+ .policy = cttimeout_nla_policy
+ },
+ [IPCTNL_MSG_TIMEOUT_DEFAULT_GET] = {
+ .call = cttimeout_default_get,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = CTA_TIMEOUT_MAX,
+ .policy = cttimeout_nla_policy
+ },
};
static const struct nfnetlink_subsystem cttimeout_subsys = {
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index d5f458d0ff3d..587086b18c36 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -845,10 +845,8 @@ static struct notifier_block nfulnl_rtnl_notifier = {
.notifier_call = nfulnl_rcv_nl_event,
};
-static int nfulnl_recv_unsupp(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nfqa[],
- struct netlink_ext_ack *extack)
+static int nfulnl_recv_unsupp(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nfula[])
{
return -ENOTSUPP;
}
@@ -869,18 +867,16 @@ static const struct nla_policy nfula_cfg_policy[NFULA_CFG_MAX+1] = {
[NFULA_CFG_FLAGS] = { .type = NLA_U16 },
};
-static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nfula[],
- struct netlink_ext_ack *extack)
+static int nfulnl_recv_config(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nfula[])
{
- struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ struct nfnl_log_net *log = nfnl_log_pernet(info->net);
+ struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int16_t group_num = ntohs(nfmsg->res_id);
- struct nfulnl_instance *inst;
struct nfulnl_msg_config_cmd *cmd = NULL;
- struct nfnl_log_net *log = nfnl_log_pernet(net);
- int ret = 0;
+ struct nfulnl_instance *inst;
u16 flags = 0;
+ int ret = 0;
if (nfula[NFULA_CFG_CMD]) {
u_int8_t pf = nfmsg->nfgen_family;
@@ -889,9 +885,9 @@ static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
/* Commands without queue context */
switch (cmd->command) {
case NFULNL_CFG_CMD_PF_BIND:
- return nf_log_bind_pf(net, pf, &nfulnl_logger);
+ return nf_log_bind_pf(info->net, pf, &nfulnl_logger);
case NFULNL_CFG_CMD_PF_UNBIND:
- nf_log_unbind_pf(net, pf);
+ nf_log_unbind_pf(info->net, pf);
return 0;
}
}
@@ -932,7 +928,7 @@ static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
goto out_put;
}
- inst = instance_create(net, group_num,
+ inst = instance_create(info->net, group_num,
NETLINK_CB(skb).portid,
sk_user_ns(NETLINK_CB(skb).sk));
if (IS_ERR(inst)) {
@@ -993,11 +989,17 @@ out:
}
static const struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = {
- [NFULNL_MSG_PACKET] = { .call = nfulnl_recv_unsupp,
- .attr_count = NFULA_MAX, },
- [NFULNL_MSG_CONFIG] = { .call = nfulnl_recv_config,
- .attr_count = NFULA_CFG_MAX,
- .policy = nfula_cfg_policy },
+ [NFULNL_MSG_PACKET] = {
+ .call = nfulnl_recv_unsupp,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = NFULA_MAX,
+ },
+ [NFULNL_MSG_CONFIG] = {
+ .call = nfulnl_recv_config,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = NFULA_CFG_MAX,
+ .policy = nfula_cfg_policy
+ },
};
static const struct nfnetlink_subsystem nfulnl_subsys = {
diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c
index 916a3c7f9eaf..e8f8875c6884 100644
--- a/net/netfilter/nfnetlink_osf.c
+++ b/net/netfilter/nfnetlink_osf.c
@@ -292,10 +292,9 @@ static const struct nla_policy nfnl_osf_policy[OSF_ATTR_MAX + 1] = {
[OSF_ATTR_FINGER] = { .len = sizeof(struct nf_osf_user_finger) },
};
-static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const osf_attrs[],
- struct netlink_ext_ack *extack)
+static int nfnl_osf_add_callback(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const osf_attrs[])
{
struct nf_osf_user_finger *f;
struct nf_osf_finger *kf = NULL, *sf;
@@ -307,7 +306,7 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
if (!osf_attrs[OSF_ATTR_FINGER])
return -EINVAL;
- if (!(nlh->nlmsg_flags & NLM_F_CREATE))
+ if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
return -EINVAL;
f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
@@ -325,7 +324,7 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
kfree(kf);
kf = NULL;
- if (nlh->nlmsg_flags & NLM_F_EXCL)
+ if (info->nlh->nlmsg_flags & NLM_F_EXCL)
err = -EEXIST;
break;
}
@@ -339,11 +338,9 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
return err;
}
-static int nfnl_osf_remove_callback(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const osf_attrs[],
- struct netlink_ext_ack *extack)
+static int nfnl_osf_remove_callback(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const osf_attrs[])
{
struct nf_osf_user_finger *f;
struct nf_osf_finger *sf;
@@ -377,11 +374,13 @@ static int nfnl_osf_remove_callback(struct net *net, struct sock *ctnl,
static const struct nfnl_callback nfnl_osf_callbacks[OSF_MSG_MAX] = {
[OSF_MSG_ADD] = {
.call = nfnl_osf_add_callback,
+ .type = NFNL_CB_MUTEX,
.attr_count = OSF_ATTR_MAX,
.policy = nfnl_osf_policy,
},
[OSF_MSG_REMOVE] = {
.call = nfnl_osf_remove_callback,
+ .type = NFNL_CB_MUTEX,
.attr_count = OSF_ATTR_MAX,
.policy = nfnl_osf_policy,
},
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 37e81d895e61..f37a575ebd7f 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1046,20 +1046,18 @@ static int nfq_id_after(unsigned int id, unsigned int max)
return (int)(id - max) > 0;
}
-static int nfqnl_recv_verdict_batch(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nfqa[],
- struct netlink_ext_ack *extack)
+static int nfqnl_recv_verdict_batch(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const nfqa[])
{
- struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ struct nfnl_queue_net *q = nfnl_queue_pernet(info->net);
+ struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
+ u16 queue_num = ntohs(nfmsg->res_id);
struct nf_queue_entry *entry, *tmp;
- unsigned int verdict, maxid;
struct nfqnl_msg_verdict_hdr *vhdr;
struct nfqnl_instance *queue;
+ unsigned int verdict, maxid;
LIST_HEAD(batch_list);
- u16 queue_num = ntohs(nfmsg->res_id);
- struct nfnl_queue_net *q = nfnl_queue_pernet(net);
queue = verdict_instance_lookup(q, queue_num,
NETLINK_CB(skb).portid);
@@ -1158,22 +1156,19 @@ static int nfqa_parse_bridge(struct nf_queue_entry *entry,
return 0;
}
-static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl,
- struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nfqa[],
- struct netlink_ext_ack *extack)
+static int nfqnl_recv_verdict(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nfqa[])
{
- struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ struct nfnl_queue_net *q = nfnl_queue_pernet(info->net);
+ struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id);
struct nfqnl_msg_verdict_hdr *vhdr;
+ enum ip_conntrack_info ctinfo;
struct nfqnl_instance *queue;
- unsigned int verdict;
struct nf_queue_entry *entry;
- enum ip_conntrack_info ctinfo;
struct nfnl_ct_hook *nfnl_ct;
struct nf_conn *ct = NULL;
- struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+ unsigned int verdict;
int err;
queue = verdict_instance_lookup(q, queue_num,
@@ -1196,7 +1191,8 @@ static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl,
if (nfqa[NFQA_CT]) {
if (nfnl_ct != NULL)
- ct = nfqnl_ct_parse(nfnl_ct, nlh, nfqa, entry, &ctinfo);
+ ct = nfqnl_ct_parse(nfnl_ct, info->nlh, nfqa, entry,
+ &ctinfo);
}
if (entry->state.pf == PF_BRIDGE) {
@@ -1224,10 +1220,8 @@ static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl,
return 0;
}
-static int nfqnl_recv_unsupp(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nfqa[],
- struct netlink_ext_ack *extack)
+static int nfqnl_recv_unsupp(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const cda[])
{
return -ENOTSUPP;
}
@@ -1245,16 +1239,14 @@ static const struct nf_queue_handler nfqh = {
.nf_hook_drop = nfqnl_nf_hook_drop,
};
-static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const nfqa[],
- struct netlink_ext_ack *extack)
+static int nfqnl_recv_config(struct sk_buff *skb, const struct nfnl_info *info,
+ const struct nlattr * const nfqa[])
{
- struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ struct nfnl_queue_net *q = nfnl_queue_pernet(info->net);
+ struct nfgenmsg *nfmsg = nlmsg_data(info->nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id);
- struct nfqnl_instance *queue;
struct nfqnl_msg_config_cmd *cmd = NULL;
- struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+ struct nfqnl_instance *queue;
__u32 flags = 0, mask = 0;
int ret = 0;
@@ -1373,17 +1365,29 @@ err_out_unlock:
}
static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
- [NFQNL_MSG_PACKET] = { .call_rcu = nfqnl_recv_unsupp,
- .attr_count = NFQA_MAX, },
- [NFQNL_MSG_VERDICT] = { .call_rcu = nfqnl_recv_verdict,
- .attr_count = NFQA_MAX,
- .policy = nfqa_verdict_policy },
- [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config,
- .attr_count = NFQA_CFG_MAX,
- .policy = nfqa_cfg_policy },
- [NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch,
- .attr_count = NFQA_MAX,
- .policy = nfqa_verdict_batch_policy },
+ [NFQNL_MSG_PACKET] = {
+ .call = nfqnl_recv_unsupp,
+ .type = NFNL_CB_RCU,
+ .attr_count = NFQA_MAX,
+ },
+ [NFQNL_MSG_VERDICT] = {
+ .call = nfqnl_recv_verdict,
+ .type = NFNL_CB_RCU,
+ .attr_count = NFQA_MAX,
+ .policy = nfqa_verdict_policy
+ },
+ [NFQNL_MSG_CONFIG] = {
+ .call = nfqnl_recv_config,
+ .type = NFNL_CB_MUTEX,
+ .attr_count = NFQA_CFG_MAX,
+ .policy = nfqa_cfg_policy
+ },
+ [NFQNL_MSG_VERDICT_BATCH] = {
+ .call = nfqnl_recv_verdict_batch,
+ .type = NFNL_CB_RCU,
+ .attr_count = NFQA_MAX,
+ .policy = nfqa_verdict_batch_policy
+ },
};
static const struct nfnetlink_subsystem nfqnl_subsys = {
diff --git a/net/netfilter/nft_chain_filter.c b/net/netfilter/nft_chain_filter.c
index 7a9aa57b195b..363bdd7044ec 100644
--- a/net/netfilter/nft_chain_filter.c
+++ b/net/netfilter/nft_chain_filter.c
@@ -2,7 +2,6 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <net/net_namespace.h>
-#include <net/netns/generic.h>
#include <net/netfilter/nf_tables.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
@@ -11,8 +10,6 @@
#include <net/netfilter/nf_tables_ipv4.h>
#include <net/netfilter/nf_tables_ipv6.h>
-extern unsigned int nf_tables_net_id;
-
#ifdef CONFIG_NF_TABLES_IPV4
static unsigned int nft_do_chain_ipv4(void *priv,
struct sk_buff *skb,
@@ -369,7 +366,7 @@ static int nf_tables_netdev_event(struct notifier_block *this,
event != NETDEV_CHANGENAME)
return NOTIFY_DONE;
- nft_net = net_generic(ctx.net, nf_tables_net_id);
+ nft_net = nft_pernet(ctx.net);
mutex_lock(&nft_net->commit_mutex);
list_for_each_entry(table, &nft_net->tables, list) {
if (table->family != NFPROTO_NETDEV)
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c
index b8dbd20a6a4c..5415ab14400d 100644
--- a/net/netfilter/nft_compat.c
+++ b/net/netfilter/nft_compat.c
@@ -613,17 +613,15 @@ nla_put_failure:
return -1;
}
-static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl,
- struct sk_buff *skb, const struct nlmsghdr *nlh,
- const struct nlattr * const tb[],
- struct netlink_ext_ack *extack)
+static int nfnl_compat_get_rcu(struct sk_buff *skb,
+ const struct nfnl_info *info,
+ const struct nlattr * const tb[])
{
- int ret = 0, target;
struct nfgenmsg *nfmsg;
- const char *fmt;
- const char *name;
- u32 rev;
+ const char *name, *fmt;
struct sk_buff *skb2;
+ int ret = 0, target;
+ u32 rev;
if (tb[NFTA_COMPAT_NAME] == NULL ||
tb[NFTA_COMPAT_REV] == NULL ||
@@ -634,7 +632,7 @@ static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl,
rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV]));
target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));
- nfmsg = nlmsg_data(nlh);
+ nfmsg = nlmsg_data(info->nlh);
switch(nfmsg->nfgen_family) {
case AF_INET:
@@ -673,8 +671,8 @@ static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl,
/* include the best revision for this extension in the message */
if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq,
- NFNL_MSG_TYPE(nlh->nlmsg_type),
+ info->nlh->nlmsg_seq,
+ NFNL_MSG_TYPE(info->nlh->nlmsg_type),
NFNL_MSG_COMPAT_GET,
nfmsg->nfgen_family,
name, ret, target) <= 0) {
@@ -682,8 +680,8 @@ static int nfnl_compat_get_rcu(struct net *net, struct sock *nfnl,
goto out_put;
}
- ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
- MSG_DONTWAIT);
+ ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
+ MSG_DONTWAIT);
if (ret > 0)
ret = 0;
out_put:
@@ -700,9 +698,12 @@ static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = {
};
static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = {
- [NFNL_MSG_COMPAT_GET] = { .call_rcu = nfnl_compat_get_rcu,
- .attr_count = NFTA_COMPAT_MAX,
- .policy = nfnl_compat_policy_get },
+ [NFNL_MSG_COMPAT_GET] = {
+ .call = nfnl_compat_get_rcu,
+ .type = NFNL_CB_RCU,
+ .attr_count = NFTA_COMPAT_MAX,
+ .policy = nfnl_compat_policy_get
+ },
};
static const struct nfnetlink_subsystem nfnl_compat_subsys = {
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index f9437a0dcfef..6ba3256fa844 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -11,9 +11,6 @@
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_core.h>
-#include <net/netns/generic.h>
-
-extern unsigned int nf_tables_net_id;
struct nft_dynset {
struct nft_set *set;
@@ -164,7 +161,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
const struct nft_expr *expr,
const struct nlattr * const tb[])
{
- struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+ struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct nft_dynset *priv = nft_expr_priv(expr);
u8 genmask = nft_genmask_next(ctx->net);
struct nft_set *set;
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
index b0f558b4fea5..a479f8a1270c 100644
--- a/net/netfilter/nft_lookup.c
+++ b/net/netfilter/nft_lookup.c
@@ -30,13 +30,17 @@ void nft_lookup_eval(const struct nft_expr *expr,
const struct nft_lookup *priv = nft_expr_priv(expr);
const struct nft_set *set = priv->set;
const struct nft_set_ext *ext = NULL;
+ const struct net *net = nft_net(pkt);
bool found;
- found = set->ops->lookup(nft_net(pkt), set, &regs->data[priv->sreg],
- &ext) ^ priv->invert;
+ found = set->ops->lookup(net, set, &regs->data[priv->sreg], &ext) ^
+ priv->invert;
if (!found) {
- regs->verdict.code = NFT_BREAK;
- return;
+ ext = nft_set_catchall_lookup(net, set);
+ if (!ext) {
+ regs->verdict.code = NFT_BREAK;
+ return;
+ }
}
if (ext) {
diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c
index bc104d36d3bb..7e47edee88ee 100644
--- a/net/netfilter/nft_objref.c
+++ b/net/netfilter/nft_objref.c
@@ -105,15 +105,18 @@ static void nft_objref_map_eval(const struct nft_expr *expr,
{
struct nft_objref_map *priv = nft_expr_priv(expr);
const struct nft_set *set = priv->set;
+ struct net *net = nft_net(pkt);
const struct nft_set_ext *ext;
struct nft_object *obj;
bool found;
- found = set->ops->lookup(nft_net(pkt), set, &regs->data[priv->sreg],
- &ext);
+ found = set->ops->lookup(net, set, &regs->data[priv->sreg], &ext);
if (!found) {
- regs->verdict.code = NFT_BREAK;
- return;
+ ext = nft_set_catchall_lookup(net, set);
+ if (!ext) {
+ regs->verdict.code = NFT_BREAK;
+ return;
+ }
}
obj = *nft_set_ext_obj(ext);
obj->ops->eval(obj, regs, pkt);
diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
index bf618b7ec1ae..58f576abcd4a 100644
--- a/net/netfilter/nft_set_hash.c
+++ b/net/netfilter/nft_set_hash.c
@@ -350,6 +350,12 @@ needs_gc_run:
rhashtable_walk_stop(&hti);
rhashtable_walk_exit(&hti);
+ he = nft_set_catchall_gc(set);
+ if (he) {
+ gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC);
+ if (gcb)
+ nft_set_gc_batch_add(gcb, he);
+ }
nft_set_gc_batch_complete(gcb);
queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
nft_set_gc_interval(set));
diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
index 9944523f5c2c..528a2d7ca991 100644
--- a/net/netfilter/nft_set_pipapo.c
+++ b/net/netfilter/nft_set_pipapo.c
@@ -1529,11 +1529,11 @@ static void pipapo_gc(const struct nft_set *set, struct nft_pipapo_match *m)
{
struct nft_pipapo *priv = nft_set_priv(set);
int rules_f0, first_rule = 0;
+ struct nft_pipapo_elem *e;
while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
struct nft_pipapo_field *f;
- struct nft_pipapo_elem *e;
int i, start, rules_fx;
start = first_rule;
@@ -1569,6 +1569,10 @@ static void pipapo_gc(const struct nft_set *set, struct nft_pipapo_match *m)
}
}
+ e = nft_set_catchall_gc(set);
+ if (e)
+ nft_set_elem_destroy(set, e, true);
+
priv->last_gc = jiffies;
}
diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c
index 217ab3644c25..9e36eb4a7429 100644
--- a/net/netfilter/nft_set_rbtree.c
+++ b/net/netfilter/nft_set_rbtree.c
@@ -541,6 +541,12 @@ static void nft_rbtree_gc(struct work_struct *work)
write_seqcount_end(&priv->count);
write_unlock_bh(&priv->lock);
+ rbe = nft_set_catchall_gc(set);
+ if (rbe) {
+ gcb = nft_set_gc_batch_check(set, gcb, GFP_ATOMIC);
+ if (gcb)
+ nft_set_gc_batch_add(gcb, rbe);
+ }
nft_set_gc_batch_complete(gcb);
queue_delayed_work(system_power_efficient_wq, &priv->gc_work,
diff --git a/net/netfilter/nft_socket.c b/net/netfilter/nft_socket.c
index c9b8a2b03b71..d601974c9d2e 100644
--- a/net/netfilter/nft_socket.c
+++ b/net/netfilter/nft_socket.c
@@ -9,6 +9,7 @@
struct nft_socket {
enum nft_socket_keys key:8;
+ u8 level;
union {
u8 dreg;
};
@@ -33,6 +34,26 @@ static void nft_socket_wildcard(const struct nft_pktinfo *pkt,
}
}
+#ifdef CONFIG_SOCK_CGROUP_DATA
+static noinline bool
+nft_sock_get_eval_cgroupv2(u32 *dest, const struct nft_pktinfo *pkt, u32 level)
+{
+ struct sock *sk = skb_to_full_sk(pkt->skb);
+ struct cgroup *cgrp;
+
+ if (!sk || !sk_fullsock(sk) || !net_eq(nft_net(pkt), sock_net(sk)))
+ return false;
+
+ cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
+ if (level > cgrp->level)
+ return false;
+
+ memcpy(dest, &cgrp->ancestor_ids[level], sizeof(u64));
+
+ return true;
+}
+#endif
+
static void nft_socket_eval(const struct nft_expr *expr,
struct nft_regs *regs,
const struct nft_pktinfo *pkt)
@@ -85,6 +106,14 @@ static void nft_socket_eval(const struct nft_expr *expr,
}
nft_socket_wildcard(pkt, regs, sk, dest);
break;
+#ifdef CONFIG_SOCK_CGROUP_DATA
+ case NFT_SOCKET_CGROUPV2:
+ if (!nft_sock_get_eval_cgroupv2(dest, pkt, priv->level)) {
+ regs->verdict.code = NFT_BREAK;
+ return;
+ }
+ break;
+#endif
default:
WARN_ON(1);
regs->verdict.code = NFT_BREAK;
@@ -97,6 +126,7 @@ static void nft_socket_eval(const struct nft_expr *expr,
static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = {
[NFTA_SOCKET_KEY] = { .type = NLA_U32 },
[NFTA_SOCKET_DREG] = { .type = NLA_U32 },
+ [NFTA_SOCKET_LEVEL] = { .type = NLA_U32 },
};
static int nft_socket_init(const struct nft_ctx *ctx,
@@ -129,6 +159,22 @@ static int nft_socket_init(const struct nft_ctx *ctx,
case NFT_SOCKET_MARK:
len = sizeof(u32);
break;
+#ifdef CONFIG_CGROUPS
+ case NFT_SOCKET_CGROUPV2: {
+ unsigned int level;
+
+ if (!tb[NFTA_SOCKET_LEVEL])
+ return -EINVAL;
+
+ level = ntohl(nla_get_u32(tb[NFTA_SOCKET_LEVEL]));
+ if (level > 255)
+ return -EOPNOTSUPP;
+
+ priv->level = level;
+ len = sizeof(u64);
+ break;
+ }
+#endif
default:
return -EOPNOTSUPP;
}
@@ -146,6 +192,9 @@ static int nft_socket_dump(struct sk_buff *skb,
return -1;
if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg))
return -1;
+ if (priv->key == NFT_SOCKET_CGROUPV2 &&
+ nla_put_u32(skb, NFTA_SOCKET_LEVEL, htonl(priv->level)))
+ return -1;
return 0;
}
diff --git a/net/netfilter/nft_tproxy.c b/net/netfilter/nft_tproxy.c
index 43a5a780a6d3..accef672088c 100644
--- a/net/netfilter/nft_tproxy.c
+++ b/net/netfilter/nft_tproxy.c
@@ -263,6 +263,29 @@ static int nft_tproxy_init(const struct nft_ctx *ctx,
return 0;
}
+static void nft_tproxy_destroy(const struct nft_ctx *ctx,
+ const struct nft_expr *expr)
+{
+ const struct nft_tproxy *priv = nft_expr_priv(expr);
+
+ switch (priv->family) {
+ case NFPROTO_IPV4:
+ nf_defrag_ipv4_disable(ctx->net);
+ break;
+#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
+ case NFPROTO_IPV6:
+ nf_defrag_ipv6_disable(ctx->net);
+ break;
+#endif
+ case NFPROTO_UNSPEC:
+ nf_defrag_ipv4_disable(ctx->net);
+#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
+ nf_defrag_ipv6_disable(ctx->net);
+#endif
+ break;
+ }
+}
+
static int nft_tproxy_dump(struct sk_buff *skb,
const struct nft_expr *expr)
{
@@ -288,6 +311,7 @@ static const struct nft_expr_ops nft_tproxy_ops = {
.size = NFT_EXPR_SIZE(sizeof(struct nft_tproxy)),
.eval = nft_tproxy_eval,
.init = nft_tproxy_init,
+ .destroy = nft_tproxy_destroy,
.dump = nft_tproxy_dump,
};
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index b7f8d2ed3cc2..84e58ee501a4 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -52,7 +52,7 @@ struct xt_af {
struct mutex mutex;
struct list_head match;
struct list_head target;
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct mutex compat_mutex;
struct compat_delta *compat_tab;
unsigned int number; /* number of slots in compat_tab[] */
@@ -647,7 +647,7 @@ static bool error_tg_ok(unsigned int usersize, unsigned int kernsize,
return usersize == kernsize && strnlen(msg, msglen) < msglen;
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta)
{
struct xt_af *xp = &xt[af];
@@ -850,7 +850,7 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,
__alignof__(struct compat_xt_entry_match));
}
EXPORT_SYMBOL(xt_compat_check_entry_offsets);
-#endif /* CONFIG_COMPAT */
+#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
/**
* xt_check_entry_offsets - validate arp/ip/ip6t_entry
@@ -868,7 +868,7 @@ EXPORT_SYMBOL(xt_compat_check_entry_offsets);
* match structures are aligned, and that the last structure ends where
* the target structure begins.
*
- * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version.
+ * Also see xt_compat_check_entry_offsets for CONFIG_NETFILTER_XTABLES_COMPAT version.
*
* The arp/ip/ip6t_entry structure @base must have passed following tests:
* - it must point to a valid memory location
@@ -1059,7 +1059,7 @@ void *xt_copy_counters(sockptr_t arg, unsigned int len,
void *mem;
u64 size;
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) {
/* structures only differ in size due to alignment */
struct compat_xt_counters_info compat_tmp;
@@ -1106,7 +1106,7 @@ void *xt_copy_counters(sockptr_t arg, unsigned int len,
}
EXPORT_SYMBOL_GPL(xt_copy_counters);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
int xt_compat_target_offset(const struct xt_target *target)
{
u_int16_t csize = target->compatsize ? : target->targetsize;
@@ -1199,6 +1199,23 @@ void xt_free_table_info(struct xt_table_info *info)
}
EXPORT_SYMBOL(xt_free_table_info);
+struct xt_table *xt_find_table(struct net *net, u8 af, const char *name)
+{
+ struct xt_pernet *xt_net = net_generic(net, xt_pernet_id);
+ struct xt_table *t;
+
+ mutex_lock(&xt[af].mutex);
+ list_for_each_entry(t, &xt_net->tables[af], list) {
+ if (strcmp(t->name, name) == 0) {
+ mutex_unlock(&xt[af].mutex);
+ return t;
+ }
+ }
+ mutex_unlock(&xt[af].mutex);
+ return NULL;
+}
+EXPORT_SYMBOL(xt_find_table);
+
/* Find table by name, grabs mutex & ref. Returns ERR_PTR on error. */
struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
const char *name)
@@ -1276,7 +1293,7 @@ void xt_table_unlock(struct xt_table *table)
}
EXPORT_SYMBOL_GPL(xt_table_unlock);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
void xt_compat_lock(u_int8_t af)
{
mutex_lock(&xt[af].compat_mutex);
@@ -1481,6 +1498,7 @@ void *xt_unregister_table(struct xt_table *table)
mutex_unlock(&xt[table->af].mutex);
audit_log_nfcfg(table->name, table->af, private->number,
AUDIT_XT_OP_UNREGISTER, GFP_KERNEL);
+ kfree(table->ops);
kfree(table);
return private;
@@ -1913,7 +1931,7 @@ static int __init xt_init(void)
for (i = 0; i < NFPROTO_NUMPROTO; i++) {
mutex_init(&xt[i].mutex);
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
mutex_init(&xt[i].compat_mutex);
xt[i].compat_tab = NULL;
#endif
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index 194dc03341f3..459d0696c91a 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -200,6 +200,11 @@ static int tproxy_tg6_check(const struct xt_tgchk_param *par)
pr_info_ratelimited("Can be used only with -p tcp or -p udp\n");
return -EINVAL;
}
+
+static void tproxy_tg6_destroy(const struct xt_tgdtor_param *par)
+{
+ nf_defrag_ipv6_disable(par->net);
+}
#endif
static int tproxy_tg4_check(const struct xt_tgchk_param *par)
@@ -219,6 +224,11 @@ static int tproxy_tg4_check(const struct xt_tgchk_param *par)
return -EINVAL;
}
+static void tproxy_tg4_destroy(const struct xt_tgdtor_param *par)
+{
+ nf_defrag_ipv4_disable(par->net);
+}
+
static struct xt_target tproxy_tg_reg[] __read_mostly = {
{
.name = "TPROXY",
@@ -228,6 +238,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
.revision = 0,
.targetsize = sizeof(struct xt_tproxy_target_info),
.checkentry = tproxy_tg4_check,
+ .destroy = tproxy_tg4_destroy,
.hooks = 1 << NF_INET_PRE_ROUTING,
.me = THIS_MODULE,
},
@@ -239,6 +250,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
.revision = 1,
.targetsize = sizeof(struct xt_tproxy_target_info_v1),
.checkentry = tproxy_tg4_check,
+ .destroy = tproxy_tg4_destroy,
.hooks = 1 << NF_INET_PRE_ROUTING,
.me = THIS_MODULE,
},
@@ -251,6 +263,7 @@ static struct xt_target tproxy_tg_reg[] __read_mostly = {
.revision = 1,
.targetsize = sizeof(struct xt_tproxy_target_info_v1),
.checkentry = tproxy_tg6_check,
+ .destroy = tproxy_tg6_destroy,
.hooks = 1 << NF_INET_PRE_ROUTING,
.me = THIS_MODULE,
},
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
index bd1dea9c7b88..24d4afb9988d 100644
--- a/net/netfilter/xt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -134,7 +134,7 @@ static void limit_mt_destroy(const struct xt_mtdtor_param *par)
kfree(info->master);
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_xt_rateinfo {
u_int32_t avg;
u_int32_t burst;
@@ -176,7 +176,7 @@ static int limit_mt_compat_to_user(void __user *dst, const void *src)
};
return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
}
-#endif /* CONFIG_COMPAT */
+#endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
static struct xt_match limit_mt_reg __read_mostly = {
.name = "limit",
@@ -186,7 +186,7 @@ static struct xt_match limit_mt_reg __read_mostly = {
.checkentry = limit_mt_check,
.destroy = limit_mt_destroy,
.matchsize = sizeof(struct xt_rateinfo),
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_xt_rateinfo),
.compat_from_user = limit_mt_compat_from_user,
.compat_to_user = limit_mt_compat_to_user,
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 5f973987265d..5e6459e11605 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -216,6 +216,14 @@ static int socket_mt_v3_check(const struct xt_mtchk_param *par)
return 0;
}
+static void socket_mt_destroy(const struct xt_mtdtor_param *par)
+{
+ if (par->family == NFPROTO_IPV4)
+ nf_defrag_ipv4_disable(par->net);
+ else if (par->family == NFPROTO_IPV6)
+ nf_defrag_ipv4_disable(par->net);
+}
+
static struct xt_match socket_mt_reg[] __read_mostly = {
{
.name = "socket",
@@ -231,6 +239,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.revision = 1,
.family = NFPROTO_IPV4,
.match = socket_mt4_v1_v2_v3,
+ .destroy = socket_mt_destroy,
.checkentry = socket_mt_v1_check,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) |
@@ -245,6 +254,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.match = socket_mt6_v1_v2_v3,
.checkentry = socket_mt_v1_check,
.matchsize = sizeof(struct xt_socket_mtinfo1),
+ .destroy = socket_mt_destroy,
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),
.me = THIS_MODULE,
@@ -256,6 +266,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV4,
.match = socket_mt4_v1_v2_v3,
.checkentry = socket_mt_v2_check,
+ .destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),
@@ -268,6 +279,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV6,
.match = socket_mt6_v1_v2_v3,
.checkentry = socket_mt_v2_check,
+ .destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),
@@ -280,6 +292,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV4,
.match = socket_mt4_v1_v2_v3,
.checkentry = socket_mt_v3_check,
+ .destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),
@@ -292,6 +305,7 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
.family = NFPROTO_IPV6,
.match = socket_mt6_v1_v2_v3,
.checkentry = socket_mt_v3_check,
+ .destroy = socket_mt_destroy,
.matchsize = sizeof(struct xt_socket_mtinfo1),
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_IN),
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c
index 1150731126e2..3982fa084737 100644
--- a/net/nfc/digital_dep.c
+++ b/net/nfc/digital_dep.c
@@ -1273,6 +1273,8 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
}
rc = nfc_tm_data_received(ddev->nfc_dev, resp);
+ if (rc)
+ resp = NULL;
exit:
kfree_skb(ddev->chaining_skb);
diff --git a/net/openvswitch/meter.c b/net/openvswitch/meter.c
index 15424d26e85d..96b524ceabca 100644
--- a/net/openvswitch/meter.c
+++ b/net/openvswitch/meter.c
@@ -392,7 +392,7 @@ static struct dp_meter *dp_meter_create(struct nlattr **a)
*
* Start with a full bucket.
*/
- band->bucket = (band->burst_size + band->rate) * 1000ULL;
+ band->bucket = band->burst_size * 1000ULL;
band_max_delta_t = div_u64(band->bucket, band->rate);
if (band_max_delta_t > meter->max_delta_t)
meter->max_delta_t = band_max_delta_t;
@@ -641,7 +641,7 @@ bool ovs_meter_execute(struct datapath *dp, struct sk_buff *skb,
long long int max_bucket_size;
band = &meter->bands[i];
- max_bucket_size = (band->burst_size + band->rate) * 1000LL;
+ max_bucket_size = band->burst_size * 1000LL;
band->bucket += delta_ms * band->rate;
if (band->bucket > max_bucket_size)
diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c
index 2bf2b1943e61..fa611678af05 100644
--- a/net/qrtr/mhi.c
+++ b/net/qrtr/mhi.c
@@ -50,6 +50,9 @@ static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
struct qrtr_mhi_dev *qdev = container_of(ep, struct qrtr_mhi_dev, ep);
int rc;
+ if (skb->sk)
+ sock_hold(skb->sk);
+
rc = skb_linearize(skb);
if (rc)
goto free_skb;
@@ -59,12 +62,11 @@ static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
if (rc)
goto free_skb;
- if (skb->sk)
- sock_hold(skb->sk);
-
return rc;
free_skb:
+ if (skb->sk)
+ sock_put(skb->sk);
kfree_skb(skb);
return rc;
diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c
index 92b4a8689aae..4190b90ff3b1 100644
--- a/net/rds/ib_send.c
+++ b/net/rds/ib_send.c
@@ -294,7 +294,6 @@ void rds_ib_send_cqe_handler(struct rds_ib_connection *ic, struct ib_wc *wc)
rds_ib_ring_free(&ic->i_send_ring, completed);
rds_ib_sub_signaled(ic, nr_sig);
- nr_sig = 0;
if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags) ||
test_bit(0, &conn->c_map_queued))
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index e2e9e9b0a6d7..08aab5c01437 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -482,7 +482,6 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
RXKADDATALEN);
goto protocol_error;
}
- offset += sizeof(sechdr);
len -= sizeof(sechdr);
buf = ntohl(sechdr.data_size);
@@ -576,7 +575,6 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
RXKADDATALEN);
goto protocol_error;
}
- offset += sizeof(sechdr);
len -= sizeof(sechdr);
buf = ntohl(sechdr.data_size);
diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
index 16e888a9601d..48fdf7293dea 100644
--- a/net/sched/act_ct.c
+++ b/net/sched/act_ct.c
@@ -732,7 +732,8 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
#endif
}
- *qdisc_skb_cb(skb) = cb;
+ if (err != -EINPROGRESS)
+ *qdisc_skb_cb(skb) = cb;
skb_clear_hash(skb);
skb->ignore_df = 1;
return err;
@@ -967,7 +968,7 @@ static int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
err = tcf_ct_handle_fragments(net, skb, family, p->zone, &defrag);
if (err == -EINPROGRESS) {
retval = TC_ACT_STOLEN;
- goto out;
+ goto out_clear;
}
if (err)
goto drop;
@@ -1030,7 +1031,6 @@ do_nat:
out_push:
skb_push_rcsum(skb, nh_ofs);
-out:
qdisc_skb_cb(skb)->post_ct = true;
out_clear:
tcf_action_update_bstats(&c->common, skb);
diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
index 922ed6b91abb..5c91df52b8c2 100644
--- a/net/sched/sch_taprio.c
+++ b/net/sched/sch_taprio.c
@@ -945,6 +945,12 @@ static int parse_taprio_schedule(struct taprio_sched *q, struct nlattr **tb,
list_for_each_entry(entry, &new->entries, list)
cycle = ktime_add_ns(cycle, entry->interval);
+
+ if (!cycle) {
+ NL_SET_ERR_MSG(extack, "'cycle_time' can never be 0");
+ return -EINVAL;
+ }
+
new->cycle_time = cycle;
}
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 47340b3b514f..be3e80b3e27f 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -1076,7 +1076,6 @@ static int smc_connect(struct socket *sock, struct sockaddr *addr,
rc = -EISCONN;
goto out;
case SMC_INIT:
- rc = 0;
break;
}
diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c
index 790c6b7ecb26..76a6f8c2eec4 100644
--- a/net/tls/tls_device.c
+++ b/net/tls/tls_device.c
@@ -418,7 +418,7 @@ static int tls_push_data(struct sock *sk,
struct tls_context *tls_ctx = tls_get_ctx(sk);
struct tls_prot_info *prot = &tls_ctx->prot_info;
struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx);
- struct tls_record_info *record = ctx->open_record;
+ struct tls_record_info *record;
int tls_push_record_flags;
struct page_frag *pfrag;
size_t orig_size = size;
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index e4370b1b7494..902cb6dd710b 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -733,6 +733,23 @@ static int virtio_transport_reset_no_sock(const struct virtio_transport *t,
return t->send_pkt(reply);
}
+/* This function should be called with sk_lock held and SOCK_DONE set */
+static void virtio_transport_remove_sock(struct vsock_sock *vsk)
+{
+ struct virtio_vsock_sock *vvs = vsk->trans;
+ struct virtio_vsock_pkt *pkt, *tmp;
+
+ /* We don't need to take rx_lock, as the socket is closing and we are
+ * removing it.
+ */
+ list_for_each_entry_safe(pkt, tmp, &vvs->rx_queue, list) {
+ list_del(&pkt->list);
+ virtio_transport_free_pkt(pkt);
+ }
+
+ vsock_remove_sock(vsk);
+}
+
static void virtio_transport_wait_close(struct sock *sk, long timeout)
{
if (timeout) {
@@ -765,7 +782,7 @@ static void virtio_transport_do_close(struct vsock_sock *vsk,
(!cancel_timeout || cancel_delayed_work(&vsk->close_work))) {
vsk->close_work_scheduled = false;
- vsock_remove_sock(vsk);
+ virtio_transport_remove_sock(vsk);
/* Release refcnt obtained when we scheduled the timeout */
sock_put(sk);
@@ -828,22 +845,15 @@ static bool virtio_transport_close(struct vsock_sock *vsk)
void virtio_transport_release(struct vsock_sock *vsk)
{
- struct virtio_vsock_sock *vvs = vsk->trans;
- struct virtio_vsock_pkt *pkt, *tmp;
struct sock *sk = &vsk->sk;
bool remove_sock = true;
if (sk->sk_type == SOCK_STREAM)
remove_sock = virtio_transport_close(vsk);
- list_for_each_entry_safe(pkt, tmp, &vvs->rx_queue, list) {
- list_del(&pkt->list);
- virtio_transport_free_pkt(pkt);
- }
-
if (remove_sock) {
sock_set_flag(sk, SOCK_DONE);
- vsock_remove_sock(vsk);
+ virtio_transport_remove_sock(vsk);
}
}
EXPORT_SYMBOL_GPL(virtio_transport_release);
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
index 8b65323207db..1c9ecb18b8e6 100644
--- a/net/vmw_vsock/vmci_transport.c
+++ b/net/vmw_vsock/vmci_transport.c
@@ -568,8 +568,7 @@ vmci_transport_queue_pair_alloc(struct vmci_qp **qpair,
peer, flags, VMCI_NO_PRIVILEGE_FLAGS);
out:
if (err < 0) {
- pr_err("Could not attach to queue pair with %d\n",
- err);
+ pr_err_once("Could not attach to queue pair with %d\n", err);
err = vmci_transport_error_to_vsock_error(err);
}