From e9d1e0219bfb5ca0645309f8c0988aa40b13f0b0 Mon Sep 17 00:00:00 2001 From: "Ycarus (Yannick Chabanois)" Date: Tue, 23 Apr 2024 20:45:31 +0200 Subject: [PATCH] Add NSS Acceleration Support on Qualcomm devices --- ...added-for-necessary-clocks-and-reset.patch | 311 +++++++ ...-gcc_snoc_bus_timeout_ahb_clk-offset.patch | 44 + ...074-Fix-gcc_blsp1_ahb_clk-properties.patch | 41 + .../0600-1-qca-nss-ecm-support-CORE.patch | 878 ++++++++++++++++++ ...-2-qca-nss-ecm-support-PPPOE-offload.patch | 600 ++++++++++++ ...00-3-qca-nss-ecm-support-net-bonding.patch | 49 + ...pport-net-bonding-over-LAG-interface.patch | 685 ++++++++++++++ .../0600-5-qca-nss-ecm-support-macvlan.patch | 96 ++ ...nss-ecm-support-netfilter-DSCPREMARK.patch | 154 +++ ...x-IPv6-user-route-change-event-calls.patch | 89 ++ ...601-1-qca-add-nss-bridge-mgr-support.patch | 92 ++ ...0602-1-qca-nss-drv-add-qdisc-support.patch | 44 + ...-1-qca-nss-clients-add-qdisc-support.patch | 441 +++++++++ ...3-2-qca-nss-clients-add-l2tp-support.patch | 46 + ...3-3-qca-nss-clients-add-PPTP-support.patch | 478 ++++++++++ ...qca-nss-clients-add-iptunnel-support.patch | 77 ++ ...-5-qca-nss-clients-add-vxlan-support.patch | 103 ++ ...-clients-add-l2tp-offloading-support.patch | 368 ++++++++ ...a-nss-clients-iptunnel-lock-this-cpu.patch | 22 + ...-qca-nss-clients-add-tls-mgr-support.patch | 24 + .../0604-1-qca-add-mcs-support.patch | 876 +++++++++++++++++ .../0605-1-qca-nss-cfi-support.patch | 111 +++ ...l-pointer-dereference-in-ipv6-output.patch | 80 ++ .../0905-ipq8074-add-blsp1-i2c4.patch | 25 + .../9990-1-qca-skb_recycler-support.patch | 412 ++++++++ ...-api-disallow-identical-driver-names.patch | 10 + .../9999-silence-UBI-NAND-warnings.patch | 13 + ...added-for-necessary-clocks-and-reset.patch | 311 +++++++ ...-gcc_snoc_bus_timeout_ahb_clk-offset.patch | 44 + ...074-Fix-gcc_blsp1_ahb_clk-properties.patch | 41 + .../0600-1-qca-nss-ecm-support-CORE.patch | 875 +++++++++++++++++ ...-2-qca-nss-ecm-support-PPPOE-offload.patch | 600 ++++++++++++ ...00-3-qca-nss-ecm-support-net-bonding.patch | 46 + ...pport-net-bonding-over-LAG-interface.patch | 685 ++++++++++++++ .../0600-5-qca-nss-ecm-support-macvlan.patch | 96 ++ ...nss-ecm-support-netfilter-DSCPREMARK.patch | 154 +++ ...x-IPv6-user-route-change-event-calls.patch | 87 ++ ...601-1-qca-add-nss-bridge-mgr-support.patch | 92 ++ ...0602-1-qca-nss-drv-add-qdisc-support.patch | 25 + ...-1-qca-nss-clients-add-qdisc-support.patch | 463 +++++++++ ...3-2-qca-nss-clients-add-l2tp-support.patch | 46 + ...3-3-qca-nss-clients-add-PPTP-support.patch | 478 ++++++++++ ...qca-nss-clients-add-iptunnel-support.patch | 77 ++ ...-5-qca-nss-clients-add-vxlan-support.patch | 103 ++ ...-clients-add-l2tp-offloading-support.patch | 368 ++++++++ ...a-nss-clients-iptunnel-lock-this-cpu.patch | 22 + ...-qca-nss-clients-add-tls-mgr-support.patch | 24 + .../0604-1-qca-add-mcs-support.patch | 876 +++++++++++++++++ .../0605-1-qca-nss-cfi-support.patch | 127 +++ ...l-pointer-dereference-in-ipv6-output.patch | 80 ++ .../9990-1-qca-skb_recycler-support.patch | 384 ++++++++ ...com-disable-swiotlb-for-64mb-savings.patch | 99 ++ ...-api-disallow-identical-driver-names.patch | 10 + .../9999-silence-UBI-NAND-warnings.patch | 13 + 54 files changed, 12395 insertions(+) create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0170-clk-qcom-ipq8074-Support-added-for-necessary-clocks-and-reset.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0171-1-clk-qcom-ipq8074-Fix-gcc_snoc_bus_timeout_ahb_clk-offset.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0171-2-clk-qcom-ipq8074-Fix-gcc_blsp1_ahb_clk-properties.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0600-1-qca-nss-ecm-support-CORE.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0600-2-qca-nss-ecm-support-PPPOE-offload.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0600-3-qca-nss-ecm-support-net-bonding.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0600-5-qca-nss-ecm-support-macvlan.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0600-6-qca-nss-ecm-support-netfilter-DSCPREMARK.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0600-7-qca-nss-ecm-fix-IPv6-user-route-change-event-calls.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0601-1-qca-add-nss-bridge-mgr-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0602-1-qca-nss-drv-add-qdisc-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0603-1-qca-nss-clients-add-qdisc-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0603-2-qca-nss-clients-add-l2tp-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0603-3-qca-nss-clients-add-PPTP-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0603-4-qca-nss-clients-add-iptunnel-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0603-5-qca-nss-clients-add-vxlan-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0603-6-qca-nss-clients-add-l2tp-offloading-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0603-7-qca-nss-clients-iptunnel-lock-this-cpu.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0603-8-qca-nss-clients-add-tls-mgr-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0604-1-qca-add-mcs-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0605-1-qca-nss-cfi-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0611-ipv6-Fix-null-pointer-dereference-in-ipv6-output.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/0905-ipq8074-add-blsp1-i2c4.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/9990-1-qca-skb_recycler-support.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/9999-revert-crypto-api-disallow-identical-driver-names.patch create mode 100644 6.1/target/linux/qualcommax/patches-6.1/9999-silence-UBI-NAND-warnings.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0170-clk-qcom-ipq8074-Support-added-for-necessary-clocks-and-reset.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0171-1-clk-qcom-ipq8074-Fix-gcc_snoc_bus_timeout_ahb_clk-offset.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0171-2-clk-qcom-ipq8074-Fix-gcc_blsp1_ahb_clk-properties.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0600-1-qca-nss-ecm-support-CORE.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0600-2-qca-nss-ecm-support-PPPOE-offload.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0600-3-qca-nss-ecm-support-net-bonding.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0600-5-qca-nss-ecm-support-macvlan.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0600-6-qca-nss-ecm-support-netfilter-DSCPREMARK.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0600-7-qca-nss-ecm-fix-IPv6-user-route-change-event-calls.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0601-1-qca-add-nss-bridge-mgr-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0602-1-qca-nss-drv-add-qdisc-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0603-1-qca-nss-clients-add-qdisc-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0603-2-qca-nss-clients-add-l2tp-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0603-3-qca-nss-clients-add-PPTP-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0603-4-qca-nss-clients-add-iptunnel-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0603-5-qca-nss-clients-add-vxlan-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0603-6-qca-nss-clients-add-l2tp-offloading-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0603-7-qca-nss-clients-iptunnel-lock-this-cpu.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0603-8-qca-nss-clients-add-tls-mgr-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0604-1-qca-add-mcs-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0605-1-qca-nss-cfi-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/0611-ipv6-Fix-null-pointer-dereference-in-ipv6-output.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/9990-1-qca-skb_recycler-support.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/9991-arm64-dts-qcom-disable-swiotlb-for-64mb-savings.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/9999-revert-crypto-api-disallow-identical-driver-names.patch create mode 100644 6.6/target/linux/qualcommax/patches-6.6/9999-silence-UBI-NAND-warnings.patch diff --git a/6.1/target/linux/qualcommax/patches-6.1/0170-clk-qcom-ipq8074-Support-added-for-necessary-clocks-and-reset.patch b/6.1/target/linux/qualcommax/patches-6.1/0170-clk-qcom-ipq8074-Support-added-for-necessary-clocks-and-reset.patch new file mode 100644 index 000000000..85430f888 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0170-clk-qcom-ipq8074-Support-added-for-necessary-clocks-and-reset.patch @@ -0,0 +1,311 @@ +From 6504bc9edeb1a2a54d813f4bb5d0267e7bf827f9 Mon Sep 17 00:00:00 2001 +From: Praveenkumar I +Date: Thu, 6 Feb 2020 17:35:42 +0530 +Subject: [PATCH 4/8] clk: ipq8074: Support added for necessary clocks and + reset + +Change-Id: I21a76a44185f766e9b6dcba274392ea8e599718b +Signed-off-by: Praveenkumar I +Signed-off-by: Rajkumar Ayyasamy +--- + drivers/clk/qcom/gcc-ipq8074.c | 238 ++++++++++++++++++- + include/dt-bindings/clock/qcom,gcc-ipq8074.h | 35 ++- + 2 files changed, 258 insertions(+), 15 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq8074.c ++++ b/drivers/clk/qcom/gcc-ipq8074.c +@@ -49,6 +49,22 @@ enum { + P_UNIPHY2_TX, + }; + ++static const char * const gcc_xo_gpll4_gpll0_gpll6_gpll0_div2[] = { ++ "xo", ++ "gpll4", ++ "gpll0", ++ "gpll6", ++ "gpll0_out_main_div2", ++}; ++ ++static const struct parent_map gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map[] = { ++ { P_XO, 0 }, ++ { P_GPLL4, 1 }, ++ { P_GPLL0, 2 }, ++ { P_GPLL6, 3 }, ++ { P_GPLL0_DIV2, 4 }, ++}; ++ + static struct clk_alpha_pll gpll0_main = { + .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], +@@ -630,6 +646,12 @@ static const struct freq_tbl ftbl_pcie_a + { } + }; + ++struct freq_tbl ftbl_pcie_rchng_clk_src[] = { ++ F(19200000, P_XO, 1, 0, 0), ++ F(100000000, P_GPLL0, 8, 0, 0), ++ { } ++}; ++ + static struct clk_rcg2 pcie0_axi_clk_src = { + .cmd_rcgr = 0x75054, + .freq_tbl = ftbl_pcie_axi_clk_src, +@@ -2030,6 +2052,78 @@ static struct clk_rcg2 gp3_clk_src = { + }, + }; + ++struct freq_tbl ftbl_qdss_tsctr_clk_src[] = { ++ F(160000000, P_GPLL0_DIV2, 2.5, 0, 0), ++ F(320000000, P_GPLL0, 2.5, 0, 0), ++ F(600000000, P_GPLL6, 2, 0, 0), ++ { } ++}; ++ ++struct clk_rcg2 qdss_tsctr_clk_src = { ++ .cmd_rcgr = 0x29064, ++ .freq_tbl = ftbl_qdss_tsctr_clk_src, ++ .hid_width = 5, ++ .parent_map = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map, ++ .clkr.hw.init = &(struct clk_init_data){ ++ .name = "qdss_tsctr_clk_src", ++ .parent_names = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2, ++ .num_parents = 5, ++ .ops = &clk_rcg2_ops, ++ }, ++}; ++ ++static struct clk_fixed_factor qdss_dap_sync_clk_src = { ++ .mult = 1, ++ .div = 4, ++ .hw.init = &(struct clk_init_data){ ++ .name = "qdss_dap_sync_clk_src", ++ .parent_names = (const char *[]){ ++ "qdss_tsctr_clk_src" ++ }, ++ .num_parents = 1, ++ .ops = &clk_fixed_factor_ops, ++ }, ++}; ++ ++struct freq_tbl ftbl_qdss_at_clk_src[] = { ++ F(66670000, P_GPLL0_DIV2, 6, 0, 0), ++ F(240000000, P_GPLL6, 6, 0, 0), ++ { } ++}; ++ ++struct clk_rcg2 qdss_at_clk_src = { ++ .cmd_rcgr = 0x2900c, ++ .freq_tbl = ftbl_qdss_at_clk_src, ++ .hid_width = 5, ++ .parent_map = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map, ++ .clkr.hw.init = &(struct clk_init_data){ ++ .name = "qdss_at_clk_src", ++ .parent_names = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2, ++ .num_parents = 5, ++ .ops = &clk_rcg2_ops, ++ }, ++}; ++ ++ ++struct freq_tbl ftbl_adss_pwm_clk_src[] = { ++ F(19200000, P_XO, 1, 0, 0), ++ F(200000000, P_GPLL0, 4, 0, 0), ++ { } ++}; ++ ++struct clk_rcg2 adss_pwm_clk_src = { ++ .cmd_rcgr = 0x1c008, ++ .freq_tbl = ftbl_adss_pwm_clk_src, ++ .hid_width = 5, ++ .parent_map = gcc_xo_gpll0_map, ++ .clkr.hw.init = &(struct clk_init_data){ ++ .name = "adss_pwm_clk_src", ++ .parent_data = gcc_xo_gpll0, ++ .num_parents = 2, ++ .ops = &clk_rcg2_ops, ++ }, ++}; ++ + static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x01008, + .clkr = { +@@ -4225,13 +4319,7 @@ static struct clk_branch gcc_gp3_clk = { + }, + }; + +-static const struct freq_tbl ftbl_pcie_rchng_clk_src[] = { +- F(19200000, P_XO, 1, 0, 0), +- F(100000000, P_GPLL0, 8, 0, 0), +- { } +-}; +- +-static struct clk_rcg2 pcie0_rchng_clk_src = { ++struct clk_rcg2 pcie0_rchng_clk_src = { + .cmd_rcgr = 0x75070, + .freq_tbl = ftbl_pcie_rchng_clk_src, + .hid_width = 5, +@@ -4323,6 +4411,114 @@ static const struct alpha_pll_config nss + .alpha_en_mask = BIT(24), + }; + ++static struct clk_branch gcc_snoc_bus_timeout2_ahb_clk = { ++ .halt_reg = 0x4700c, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x4700c, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_snoc_bus_timeout2_ahb_clk", ++ .parent_names = (const char *[]){ ++ "usb0_master_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch gcc_snoc_bus_timeout3_ahb_clk = { ++ .halt_reg = 0x47014, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x47014, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_snoc_bus_timeout3_ahb_clk", ++ .parent_names = (const char *[]){ ++ "usb1_master_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch gcc_dcc_clk = { ++ .halt_reg = 0x77004, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x77004, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_dcc_clk", ++ .parent_names = (const char *[]){ ++ "pcnoc_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch gcc_qdss_at_clk = { ++ .halt_reg = 0x29024, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x29024, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_qdss_at_clk", ++ .parent_names = (const char *[]){ ++ "qdss_at_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch gcc_qdss_dap_clk = { ++ .halt_reg = 0x29084, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x29084, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_qdss_dap_clk", ++ .parent_names = (const char *[]){ ++ "qdss_dap_sync_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch gcc_adss_pwm_clk = { ++ .halt_reg = 0x1c020, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x1c020, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_adss_pwm_clk", ++ .parent_names = (const char *[]){ ++ "adss_pwm_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ + static struct clk_hw *gcc_ipq8074_hws[] = { + &gpll0_out_main_div2.hw, + &gpll6_out_main_div2.hw, +@@ -4331,6 +4527,7 @@ static struct clk_hw *gcc_ipq8074_hws[] + &gcc_xo_div4_clk_src.hw, + &nss_noc_clk_src.hw, + &nss_ppe_cdiv_clk_src.hw, ++ &qdss_dap_sync_clk_src.hw, + }; + + static struct clk_regmap *gcc_ipq8074_clks[] = { +@@ -4562,6 +4759,15 @@ static struct clk_regmap *gcc_ipq8074_cl + [GCC_PCIE0_RCHNG_CLK] = &gcc_pcie0_rchng_clk.clkr, + [GCC_PCIE0_AXI_S_BRIDGE_CLK] = &gcc_pcie0_axi_s_bridge_clk.clkr, + [GCC_CRYPTO_PPE_CLK] = &gcc_crypto_ppe_clk.clkr, ++ [GCC_SNOC_BUS_TIMEOUT2_AHB_CLK] = &gcc_snoc_bus_timeout2_ahb_clk.clkr, ++ [GCC_SNOC_BUS_TIMEOUT3_AHB_CLK] = &gcc_snoc_bus_timeout3_ahb_clk.clkr, ++ [GCC_DCC_CLK] = &gcc_dcc_clk.clkr, ++ [QDSS_TSCTR_CLK_SRC] = &qdss_tsctr_clk_src.clkr, ++ [QDSS_AT_CLK_SRC] = &qdss_at_clk_src.clkr, ++ [GCC_QDSS_AT_CLK] = &gcc_qdss_at_clk.clkr, ++ [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr, ++ [ADSS_PWM_CLK_SRC] = &adss_pwm_clk_src.clkr, ++ [GCC_ADSS_PWM_CLK] = &gcc_adss_pwm_clk.clkr, + }; + + static const struct qcom_reset_map gcc_ipq8074_resets[] = { +--- a/include/dt-bindings/clock/qcom,gcc-ipq8074.h ++++ b/include/dt-bindings/clock/qcom,gcc-ipq8074.h +@@ -230,10 +230,19 @@ + #define GCC_GP1_CLK 221 + #define GCC_GP2_CLK 222 + #define GCC_GP3_CLK 223 +-#define GCC_PCIE0_AXI_S_BRIDGE_CLK 224 +-#define GCC_PCIE0_RCHNG_CLK_SRC 225 +-#define GCC_PCIE0_RCHNG_CLK 226 +-#define GCC_CRYPTO_PPE_CLK 227 ++#define GCC_CRYPTO_PPE_CLK 224 ++#define GCC_PCIE0_RCHNG_CLK_SRC 225 ++#define GCC_PCIE0_RCHNG_CLK 226 ++#define GCC_PCIE0_AXI_S_BRIDGE_CLK 227 ++#define GCC_SNOC_BUS_TIMEOUT2_AHB_CLK 228 ++#define GCC_SNOC_BUS_TIMEOUT3_AHB_CLK 229 ++#define GCC_DCC_CLK 230 ++#define ADSS_PWM_CLK_SRC 231 ++#define GCC_ADSS_PWM_CLK 232 ++#define QDSS_TSCTR_CLK_SRC 233 ++#define QDSS_AT_CLK_SRC 234 ++#define GCC_QDSS_AT_CLK 235 ++#define GCC_QDSS_DAP_CLK 236 + + #define GCC_BLSP1_BCR 0 + #define GCC_BLSP1_QUP1_BCR 1 diff --git a/6.1/target/linux/qualcommax/patches-6.1/0171-1-clk-qcom-ipq8074-Fix-gcc_snoc_bus_timeout_ahb_clk-offset.patch b/6.1/target/linux/qualcommax/patches-6.1/0171-1-clk-qcom-ipq8074-Fix-gcc_snoc_bus_timeout_ahb_clk-offset.patch new file mode 100644 index 000000000..7aae767ee --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0171-1-clk-qcom-ipq8074-Fix-gcc_snoc_bus_timeout_ahb_clk-offset.patch @@ -0,0 +1,44 @@ +From 462aa0c53397ec5bf78e3e7f68aa8a3ca300f4ba Mon Sep 17 00:00:00 2001 +From: Selvam Sathappan Periakaruppan +Date: Tue, 24 Mar 2020 19:09:38 +0530 +Subject: [PATCH 5/8] clk: qcom: ipq8074: Fix gcc_snoc_bus_timeout_ahb_clk + offset + +By default, the ipq8074 V2 clks are provided in the gcc driver. +Updating the gcc_snoc_bus_timeout_ahb_clk offsets also as needed +in ipq8074 V2. + +Change-Id: I5a6e98d002f5c3354a804e55dd9ebb1f83f7f974 +Signed-off-by: Selvam Sathappan Periakaruppan +--- + drivers/clk/qcom/gcc-ipq8074.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq8074.c ++++ b/drivers/clk/qcom/gcc-ipq8074.c +@@ -4412,10 +4412,10 @@ static const struct alpha_pll_config nss + }; + + static struct clk_branch gcc_snoc_bus_timeout2_ahb_clk = { +- .halt_reg = 0x4700c, ++ .halt_reg = 0x47014, + .halt_bit = 31, + .clkr = { +- .enable_reg = 0x4700c, ++ .enable_reg = 0x47014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_snoc_bus_timeout2_ahb_clk", +@@ -4430,10 +4430,10 @@ static struct clk_branch gcc_snoc_bus_ti + }; + + static struct clk_branch gcc_snoc_bus_timeout3_ahb_clk = { +- .halt_reg = 0x47014, ++ .halt_reg = 0x4701C, + .halt_bit = 31, + .clkr = { +- .enable_reg = 0x47014, ++ .enable_reg = 0x4701C, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_snoc_bus_timeout3_ahb_clk", diff --git a/6.1/target/linux/qualcommax/patches-6.1/0171-2-clk-qcom-ipq8074-Fix-gcc_blsp1_ahb_clk-properties.patch b/6.1/target/linux/qualcommax/patches-6.1/0171-2-clk-qcom-ipq8074-Fix-gcc_blsp1_ahb_clk-properties.patch new file mode 100644 index 000000000..3c7be3478 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0171-2-clk-qcom-ipq8074-Fix-gcc_blsp1_ahb_clk-properties.patch @@ -0,0 +1,41 @@ +From 52315bec6ed633b6a71f28b746029602f8bd70b9 Mon Sep 17 00:00:00 2001 +From: Balaji Prakash J +Date: Wed, 22 Apr 2020 20:35:30 +0530 +Subject: [PATCH] clk: ipq8074: fix gcc_blsp1_ahb_clk properties + +All the voting enabled clocks does not support the enable +from CBCR register. So, updated gcc_blsp1_ahb_clk enable +register and mask to enable bit in APCS_CLOCK_BRANCH_ENA_VOTE. + +Also, the voting controlled clocks are shared among multiple +components like APSS, RPM, NSS, TZ, etc. So, turning the +voting off from APSS does not make the clock off if it has +been voted from another component. Added the flag +BRANCH_HALT_VOTED in order to skip checking the clock +disable status. + +This change is referred from the below commits, +1. 246b4fb3af9bd65d8af794aac2f0e7b1ed9cc2dd +2. c8374157d5ae91d3b3e0d513d62808a798b32d3a + +Signed-off-by: Balaji Prakash J +Change-Id: I505cb560b31ad27a02c165fbe13bb33a2fc7d230 +--- + drivers/clk/qcom/gcc-ipq8074.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq8074.c ++++ b/drivers/clk/qcom/gcc-ipq8074.c +@@ -2126,9 +2126,10 @@ struct clk_rcg2 adss_pwm_clk_src = { + + static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x01008, ++ .halt_check = BRANCH_HALT_VOTED, + .clkr = { +- .enable_reg = 0x01008, +- .enable_mask = BIT(0), ++ .enable_reg = 0x0b004, ++ .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ diff --git a/6.1/target/linux/qualcommax/patches-6.1/0600-1-qca-nss-ecm-support-CORE.patch b/6.1/target/linux/qualcommax/patches-6.1/0600-1-qca-nss-ecm-support-CORE.patch new file mode 100644 index 000000000..a1cd66c4d --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0600-1-qca-nss-ecm-support-CORE.patch @@ -0,0 +1,878 @@ +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -69,6 +69,9 @@ void brioctl_set(int (*hook)(struct net + void __user *uarg)); + int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd, + struct ifreq *ifr, void __user *uarg); ++extern void br_dev_update_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *nlstats); ++extern bool br_is_hairpin_enabled(struct net_device *dev); + + #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) + int br_multicast_list_adjacent(struct net_device *dev, +@@ -211,4 +214,42 @@ static inline clock_t br_get_ageing_time + } + #endif + ++/* QCA NSS ECM support - Start */ ++extern struct net_device *br_port_dev_get(struct net_device *dev, ++ unsigned char *addr, ++ struct sk_buff *skb, ++ unsigned int cookie); ++extern void br_refresh_fdb_entry(struct net_device *dev, const char *addr); ++extern void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid); ++extern struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev, ++ const char *addr, ++ __u16 vid); ++extern void br_fdb_update_register_notify(struct notifier_block *nb); ++extern void br_fdb_update_unregister_notify(struct notifier_block *nb); ++ ++typedef struct net_bridge_port *br_port_dev_get_hook_t(struct net_device *dev, ++ struct sk_buff *skb, ++ unsigned char *addr, ++ unsigned int cookie); ++extern br_port_dev_get_hook_t __rcu *br_port_dev_get_hook; ++ ++#define BR_FDB_EVENT_ADD 0x01 ++#define BR_FDB_EVENT_DEL 0x02 ++ ++struct br_fdb_event { ++ struct net_device *dev; ++ unsigned char addr[6]; ++ unsigned char is_local; ++ struct net_bridge *br; ++ struct net_device *orig_dev; ++}; ++extern void br_fdb_register_notify(struct notifier_block *nb); ++extern void br_fdb_unregister_notify(struct notifier_block *nb); ++ ++typedef struct net_bridge_port *br_get_dst_hook_t( ++ const struct net_bridge_port *src, ++ struct sk_buff **skb); ++extern br_get_dst_hook_t __rcu *br_get_dst_hook; ++/* QCA NSS ECM support - End */ ++ + #endif +--- a/include/linux/if_vlan.h ++++ b/include/linux/if_vlan.h +@@ -143,7 +143,10 @@ extern struct net_device *__vlan_find_de + extern int vlan_for_each(struct net_device *dev, + int (*action)(struct net_device *dev, int vid, + void *arg), void *arg); ++extern void __vlan_dev_update_accel_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *stats); /* QCA NSS ECM support */ + extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); ++extern struct net_device *vlan_dev_next_dev(const struct net_device *dev); /* QCA NSS ECM support */ + extern u16 vlan_dev_vlan_id(const struct net_device *dev); + extern __be16 vlan_dev_vlan_proto(const struct net_device *dev); + +@@ -236,6 +239,12 @@ extern void vlan_vids_del_by_dev(struct + extern bool vlan_uses_dev(const struct net_device *dev); + + #else ++static inline void __vlan_dev_update_accel_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) ++{ ++ ++} /* QCA NSS ECM support - End */ ++ + static inline struct net_device * + __vlan_find_dev_deep_rcu(struct net_device *real_dev, + __be16 vlan_proto, u16 vlan_id) +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -2855,6 +2855,10 @@ enum netdev_cmd { + NETDEV_OFFLOAD_XSTATS_DISABLE, + NETDEV_OFFLOAD_XSTATS_REPORT_USED, + NETDEV_OFFLOAD_XSTATS_REPORT_DELTA, ++ /* QCA NSS ECM Support - Start */ ++ NETDEV_BR_JOIN, ++ NETDEV_BR_LEAVE, ++ /* QCA NSS ECM Support - End */ + }; + const char *netdev_cmd_to_name(enum netdev_cmd cmd); + +--- a/include/net/ip6_route.h ++++ b/include/net/ip6_route.h +@@ -211,6 +211,11 @@ void rt6_multipath_rebalance(struct fib6 + void rt6_uncached_list_add(struct rt6_info *rt); + void rt6_uncached_list_del(struct rt6_info *rt); + ++/* QCA NSS ECM support - Start */ ++int rt6_register_notifier(struct notifier_block *nb); ++int rt6_unregister_notifier(struct notifier_block *nb); ++/* QCA NSS ECM support - End */ ++ + static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb) + { + const struct dst_entry *dst = skb_dst(skb); +--- a/include/net/neighbour.h ++++ b/include/net/neighbour.h +@@ -249,6 +249,13 @@ static inline int neigh_parms_family(str + return p->tbl->family; + } + ++/* QCA NSS ECM support - Start */ ++struct neigh_mac_update { ++ unsigned char old_mac[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))]; ++ unsigned char update_mac[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))]; ++}; ++/* QCA NSS ECM support - End */ ++ + #define NEIGH_PRIV_ALIGN sizeof(long long) + #define NEIGH_ENTRY_SIZE(size) ALIGN((size), NEIGH_PRIV_ALIGN) + +@@ -397,6 +404,11 @@ int neigh_xmit(int fam, struct net_devic + void pneigh_for_each(struct neigh_table *tbl, + void (*cb)(struct pneigh_entry *)); + ++/* QCA NSS ECM support - Start */ ++extern void neigh_mac_update_register_notify(struct notifier_block *nb); ++extern void neigh_mac_update_unregister_notify(struct notifier_block *nb); ++/* QCA NSS ECM support - End */ ++ + struct neigh_seq_state { + struct seq_net_private p; + struct neigh_table *tbl; +@@ -602,4 +614,5 @@ static inline void neigh_update_is_route + *notify = 1; + } + } ++ + #endif +--- a/include/net/route.h ++++ b/include/net/route.h +@@ -240,6 +240,11 @@ struct rtable *rt_dst_alloc(struct net_d + unsigned int flags, u16 type, bool noxfrm); + struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt); + ++/* QCA NSS ECM support - Start */ ++int ip_rt_register_notifier(struct notifier_block *nb); ++int ip_rt_unregister_notifier(struct notifier_block *nb); ++/* QCA NSS ECM support - End */ ++ + struct in_ifaddr; + void fib_add_ifaddr(struct in_ifaddr *); + void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *); +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -2172,4 +2172,9 @@ void br_do_proxy_suppress_arp(struct sk_ + void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br, + u16 vid, struct net_bridge_port *p, struct nd_msg *msg); + struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *m); ++ ++/* QCA NSS ECM support - Start */ ++#define __br_get(__hook, __default, __args ...) \ ++ (__hook ? (__hook(__args)) : (__default)) ++/* QCA NSS ECM support - End */ + #endif +--- a/net/8021q/vlan_core.c ++++ b/net/8021q/vlan_core.c +@@ -72,6 +72,28 @@ bool vlan_do_receive(struct sk_buff **sk + return true; + } + ++/* QCA NSS ECM support - Start */ ++/* Update the VLAN device with statistics from network offload engines */ ++void __vlan_dev_update_accel_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *nlstats) ++{ ++ struct vlan_pcpu_stats *stats; ++ ++ if (!is_vlan_dev(dev)) ++ return; ++ ++ stats = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, 0); ++ ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_add(&stats->rx_packets, nlstats->rx_packets); ++ u64_stats_add(&stats->rx_bytes, nlstats->rx_bytes); ++ u64_stats_add(&stats->tx_packets, nlstats->tx_packets); ++ u64_stats_add(&stats->tx_bytes, nlstats->tx_bytes); ++ u64_stats_update_end(&stats->syncp); ++} ++EXPORT_SYMBOL(__vlan_dev_update_accel_stats); ++/* QCA NSS ECM support - End */ ++ + /* Must be invoked with rcu_read_lock. */ + struct net_device *__vlan_find_dev_deep_rcu(struct net_device *dev, + __be16 vlan_proto, u16 vlan_id) +@@ -110,6 +132,15 @@ struct net_device *vlan_dev_real_dev(con + } + EXPORT_SYMBOL(vlan_dev_real_dev); + ++/* QCA NSS ECM support - Start */ ++/* Caller is responsible to hold the reference of the returned device */ ++struct net_device *vlan_dev_next_dev(const struct net_device *dev) ++{ ++ return vlan_dev_priv(dev)->real_dev; ++} ++EXPORT_SYMBOL(vlan_dev_next_dev); ++/* QCA NSS ECM support - End */ ++ + u16 vlan_dev_vlan_id(const struct net_device *dev) + { + return vlan_dev_priv(dev)->vlan_id; +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -33,6 +33,20 @@ static const struct rhashtable_params br + + static struct kmem_cache *br_fdb_cache __read_mostly; + ++ATOMIC_NOTIFIER_HEAD(br_fdb_notifier_list); ++ ++void br_fdb_register_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_register(&br_fdb_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_register_notify); ++ ++void br_fdb_unregister_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_unregister(&br_fdb_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_unregister_notify); ++ + int __init br_fdb_init(void) + { + br_fdb_cache = kmem_cache_create("bridge_fdb_cache", +@@ -188,6 +202,25 @@ static void fdb_notify(struct net_bridge + if (swdev_notify) + br_switchdev_fdb_notify(br, fdb, type); + ++ /* QCA NSS ECM support - Start */ ++ if (fdb->dst) { ++ int event; ++ struct br_fdb_event fdb_event; ++ ++ if (type == RTM_NEWNEIGH) ++ event = BR_FDB_EVENT_ADD; ++ else ++ event = BR_FDB_EVENT_DEL; ++ ++ fdb_event.dev = fdb->dst->dev; ++ ether_addr_copy(fdb_event.addr, fdb->key.addr.addr); ++ fdb_event.is_local = test_bit(BR_FDB_LOCAL, &fdb->flags); ++ atomic_notifier_call_chain(&br_fdb_notifier_list, ++ event, ++ (void *)&fdb_event); ++ } ++ /* QCA NSS ECM support - End */ ++ + skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC); + if (skb == NULL) + goto errout; +@@ -512,6 +545,22 @@ out: + spin_unlock_bh(&br->hash_lock); + } + ++/* QCA NSS ECM support - Start */ ++ATOMIC_NOTIFIER_HEAD(br_fdb_update_notifier_list); ++ ++void br_fdb_update_register_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_register(&br_fdb_update_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_update_register_notify); ++ ++void br_fdb_update_unregister_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_unregister(&br_fdb_update_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_update_unregister_notify); ++/* QCA NSS ECM support - End */ ++ + void br_fdb_cleanup(struct work_struct *work) + { + struct net_bridge *br = container_of(work, struct net_bridge, +@@ -520,6 +569,7 @@ void br_fdb_cleanup(struct work_struct * + unsigned long delay = hold_time(br); + unsigned long work_delay = delay; + unsigned long now = jiffies; ++ u8 mac_addr[6]; /* QCA NSS ECM support */ + + /* this part is tricky, in order to avoid blocking learning and + * consequently forwarding, we rely on rcu to delete objects with +@@ -546,8 +596,15 @@ void br_fdb_cleanup(struct work_struct * + work_delay = min(work_delay, this_timer - now); + } else { + spin_lock_bh(&br->hash_lock); +- if (!hlist_unhashed(&f->fdb_node)) ++ if (!hlist_unhashed(&f->fdb_node)) { ++ ether_addr_copy(mac_addr, f->key.addr.addr); + fdb_delete(br, f, true); ++ /* QCA NSS ECM support - Start */ ++ atomic_notifier_call_chain( ++ &br_fdb_update_notifier_list, 0, ++ (void *)mac_addr); ++ /* QCA NSS ECM support - End */ ++ } + spin_unlock_bh(&br->hash_lock); + } + } +@@ -879,6 +936,12 @@ void br_fdb_update(struct net_bridge *br + &fdb->flags))) + clear_bit(BR_FDB_ADDED_BY_EXT_LEARN, + &fdb->flags); ++ ++ /* QCA NSS ECM support - Start */ ++ atomic_notifier_call_chain( ++ &br_fdb_update_notifier_list, ++ 0, (void *)addr); ++ /* QCA NSS ECM support - End */ + } + + if (unlikely(test_bit(BR_FDB_ADDED_BY_USER, &flags))) +@@ -902,6 +965,64 @@ void br_fdb_update(struct net_bridge *br + } + } + ++/* QCA NSS ECM support - Start */ ++/* Refresh FDB entries for bridge packets being forwarded by offload engines */ ++void br_refresh_fdb_entry(struct net_device *dev, const char *addr) ++{ ++ struct net_bridge_port *p = br_port_get_rcu(dev); ++ ++ if (!p || p->state == BR_STATE_DISABLED) ++ return; ++ ++ if (!is_valid_ether_addr(addr)) { ++ pr_info("bridge: Attempt to refresh with invalid ether address %pM\n", ++ addr); ++ return; ++ } ++ ++ rcu_read_lock(); ++ br_fdb_update(p->br, p, addr, 0, true); ++ rcu_read_unlock(); ++} ++EXPORT_SYMBOL_GPL(br_refresh_fdb_entry); ++ ++/* Update timestamp of FDB entries for bridge packets being forwarded by offload engines */ ++void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid) ++{ ++ struct net_bridge_fdb_entry *fdb; ++ struct net_bridge_port *p = br_port_get_rcu(dev); ++ ++ if (!p || p->state == BR_STATE_DISABLED) ++ return; ++ ++ rcu_read_lock(); ++ fdb = fdb_find_rcu(&p->br->fdb_hash_tbl, addr, vid); ++ if (likely(fdb)) { ++ fdb->updated = jiffies; ++ } ++ rcu_read_unlock(); ++} ++EXPORT_SYMBOL_GPL(br_fdb_entry_refresh); ++ ++/* Look up the MAC address in the device's bridge fdb table */ ++struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev, ++ const char *addr, __u16 vid) ++{ ++ struct net_bridge_port *p = br_port_get_rcu(dev); ++ struct net_bridge_fdb_entry *fdb; ++ ++ if (!p || p->state == BR_STATE_DISABLED) ++ return NULL; ++ ++ rcu_read_lock(); ++ fdb = fdb_find_rcu(&p->br->fdb_hash_tbl, addr, vid); ++ rcu_read_unlock(); ++ ++ return fdb; ++} ++EXPORT_SYMBOL_GPL(br_fdb_has_entry); ++ ++/* QCA NSS ECM support - End */ + /* Dump information about entries, in response to GETNEIGH */ + int br_fdb_dump(struct sk_buff *skb, + struct netlink_callback *cb, +--- a/net/bridge/br_if.c ++++ b/net/bridge/br_if.c +@@ -26,6 +26,12 @@ + + #include "br_private.h" + ++/* QCA NSS ECM support - Start */ ++/* Hook for external forwarding logic */ ++br_port_dev_get_hook_t __rcu *br_port_dev_get_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_port_dev_get_hook); ++/* QCA NSS ECM support - End */ ++ + /* + * Determine initial path cost based on speed. + * using recommendations from 802.1d standard +@@ -697,6 +703,8 @@ int br_add_if(struct net_bridge *br, str + + kobject_uevent(&p->kobj, KOBJ_ADD); + ++ call_netdevice_notifiers(NETDEV_BR_JOIN, dev); /* QCA NSS ECM support */ ++ + return 0; + + err6: +@@ -732,6 +740,8 @@ int br_del_if(struct net_bridge *br, str + if (!p || p->br != br) + return -EINVAL; + ++ call_netdevice_notifiers(NETDEV_BR_LEAVE, dev); /* QCA NSS ECM support */ ++ + /* Since more than one interface can be attached to a bridge, + * there still maybe an alternate path for netconsole to use; + * therefore there is no reason for a NETDEV_RELEASE event. +@@ -775,3 +785,97 @@ bool br_port_flag_is_set(const struct ne + return p->flags & flag; + } + EXPORT_SYMBOL_GPL(br_port_flag_is_set); ++ ++/* br_port_dev_get() ++ * If a skb is provided, and the br_port_dev_get_hook_t hook exists, ++ * use that to try and determine the egress port for that skb. ++ * If not, or no egress port could be determined, use the given addr ++ * to identify the port to which it is reachable, ++ * returing a reference to the net device associated with that port. ++ * ++ * NOTE: Return NULL if given dev is not a bridge or the mac has no ++ * associated port. ++ */ ++struct net_device *br_port_dev_get(struct net_device *dev, unsigned char *addr, ++ struct sk_buff *skb, ++ unsigned int cookie) ++{ ++ struct net_bridge_fdb_entry *fdbe; ++ struct net_bridge *br; ++ struct net_device *netdev = NULL; ++ ++ /* Is this a bridge? */ ++ if (!(dev->priv_flags & IFF_EBRIDGE)) ++ return NULL; ++ ++ rcu_read_lock(); ++ ++ /* If the hook exists and the skb isn't NULL, try and get the port */ ++ if (skb) { ++ br_port_dev_get_hook_t *port_dev_get_hook; ++ ++ port_dev_get_hook = rcu_dereference(br_port_dev_get_hook); ++ if (port_dev_get_hook) { ++ struct net_bridge_port *pdst = ++ __br_get(port_dev_get_hook, NULL, dev, skb, ++ addr, cookie); ++ if (pdst) { ++ dev_hold(pdst->dev); ++ netdev = pdst->dev; ++ goto out; ++ } ++ } ++ } ++ ++ /* Either there is no hook, or can't ++ * determine the port to use - fall back to using FDB ++ */ ++ ++ br = netdev_priv(dev); ++ ++ /* Lookup the fdb entry and get reference to the port dev */ ++ fdbe = br_fdb_find_rcu(br, addr, 0); ++ if (fdbe && fdbe->dst) { ++ netdev = fdbe->dst->dev; /* port device */ ++ dev_hold(netdev); ++ } ++out: ++ rcu_read_unlock(); ++ return netdev; ++} ++EXPORT_SYMBOL_GPL(br_port_dev_get); ++ ++/* Update bridge statistics for bridge packets processed by offload engines */ ++void br_dev_update_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *nlstats) ++{ ++ struct pcpu_sw_netstats *tstats; ++ ++ /* Is this a bridge? */ ++ if (!(dev->priv_flags & IFF_EBRIDGE)) ++ return; ++ ++ tstats = this_cpu_ptr(dev->tstats); ++ ++ u64_stats_update_begin(&tstats->syncp); ++ u64_stats_add(&tstats->rx_packets, nlstats->rx_packets); ++ u64_stats_add(&tstats->rx_bytes, nlstats->rx_bytes); ++ u64_stats_add(&tstats->tx_packets, nlstats->tx_packets); ++ u64_stats_add(&tstats->tx_bytes, nlstats->tx_bytes); ++ u64_stats_update_end(&tstats->syncp); ++} ++EXPORT_SYMBOL_GPL(br_dev_update_stats); ++ ++/* QCA NSS ECM support - Start */ ++/* API to know if hairpin feature is enabled/disabled on this bridge port */ ++bool br_is_hairpin_enabled(struct net_device *dev) ++{ ++ struct net_bridge_port *port = br_port_get_check_rcu(dev); ++ ++ if (likely(port)) ++ return port->flags & BR_HAIRPIN_MODE; ++ return false; ++} ++EXPORT_SYMBOL_GPL(br_is_hairpin_enabled); ++ ++/* QCA NSS ECM support - End */ +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -1275,6 +1275,22 @@ static void neigh_update_hhs(struct neig + } + } + ++/* QCA NSS ECM support - Start */ ++ATOMIC_NOTIFIER_HEAD(neigh_mac_update_notifier_list); ++ ++void neigh_mac_update_register_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_register(&neigh_mac_update_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(neigh_mac_update_register_notify); ++ ++void neigh_mac_update_unregister_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_unregister(&neigh_mac_update_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(neigh_mac_update_unregister_notify); ++/* QCA NSS ECM support - End */ ++ + /* Generic update routine. + -- lladdr is new lladdr or NULL, if it is not supplied. + -- new is new state. +@@ -1303,6 +1319,7 @@ static int __neigh_update(struct neighbo + struct net_device *dev; + int err, notify = 0; + u8 old; ++ struct neigh_mac_update nmu; /* QCA NSS ECM support */ + + trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid); + +@@ -1317,7 +1334,10 @@ static int __neigh_update(struct neighbo + new = old; + goto out; + } +- if (!(flags & NEIGH_UPDATE_F_ADMIN) && ++ ++ memset(&nmu, 0, sizeof(struct neigh_mac_update)); /* QCA NSS ECM support */ ++ ++ if (!(flags & NEIGH_UPDATE_F_ADMIN) && + (old & (NUD_NOARP | NUD_PERMANENT))) + goto out; + +@@ -1354,7 +1374,12 @@ static int __neigh_update(struct neighbo + - compare new & old + - if they are different, check override flag + */ +- if ((old & NUD_VALID) && ++ /* QCA NSS ECM update - Start */ ++ memcpy(nmu.old_mac, neigh->ha, dev->addr_len); ++ memcpy(nmu.update_mac, lladdr, dev->addr_len); ++ /* QCA NSS ECM update - End */ ++ ++ if ((old & NUD_VALID) && + !memcmp(lladdr, neigh->ha, dev->addr_len)) + lladdr = neigh->ha; + } else { +@@ -1476,8 +1501,11 @@ out: + neigh_update_gc_list(neigh); + if (managed_update) + neigh_update_managed_list(neigh); +- if (notify) ++ if (notify) { + neigh_update_notify(neigh, nlmsg_pid); ++ atomic_notifier_call_chain(&neigh_mac_update_notifier_list, 0, ++ (struct neigh_mac_update *)&nmu); /* QCA NSS ECM support */ ++ } + trace_neigh_update_done(neigh, err); + return err; + } +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -1211,6 +1211,9 @@ static bool fib_valid_key_len(u32 key, u + static void fib_remove_alias(struct trie *t, struct key_vector *tp, + struct key_vector *l, struct fib_alias *old); + ++/* Define route change notification chain. */ ++static BLOCKING_NOTIFIER_HEAD(iproute_chain); /* QCA NSS ECM support */ ++ + /* Caller must hold RTNL. */ + int fib_table_insert(struct net *net, struct fib_table *tb, + struct fib_config *cfg, struct netlink_ext_ack *extack) +@@ -1404,6 +1407,9 @@ int fib_table_insert(struct net *net, st + rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, new_fa->tb_id, + &cfg->fc_nlinfo, nlflags); + succeeded: ++ blocking_notifier_call_chain(&iproute_chain, ++ RTM_NEWROUTE, fi); ++ + return 0; + + out_remove_new_fa: +@@ -1775,6 +1781,9 @@ int fib_table_delete(struct net *net, st + if (fa_to_delete->fa_state & FA_S_ACCESSED) + rt_cache_flush(cfg->fc_nlinfo.nl_net); + ++ blocking_notifier_call_chain(&iproute_chain, ++ RTM_DELROUTE, fa_to_delete->fa_info); ++ + fib_release_info(fa_to_delete->fa_info); + alias_free_mem_rcu(fa_to_delete); + return 0; +@@ -2407,6 +2416,20 @@ void __init fib_trie_init(void) + 0, SLAB_PANIC | SLAB_ACCOUNT, NULL); + } + ++/* QCA NSS ECM support - Start */ ++int ip_rt_register_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register(&iproute_chain, nb); ++} ++EXPORT_SYMBOL(ip_rt_register_notifier); ++ ++int ip_rt_unregister_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_unregister(&iproute_chain, nb); ++} ++EXPORT_SYMBOL(ip_rt_unregister_notifier); ++/* QCA NSS ECM support - End */ ++ + struct fib_table *fib_trie_table(u32 id, struct fib_table *alias) + { + struct fib_table *tb; +--- a/net/ipv6/ndisc.c ++++ b/net/ipv6/ndisc.c +@@ -666,6 +666,7 @@ void ndisc_send_ns(struct net_device *de + if (skb) + ndisc_send_skb(skb, daddr, saddr); + } ++EXPORT_SYMBOL(ndisc_send_ns); + + void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, + const struct in6_addr *daddr) +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -197,6 +197,9 @@ static void rt6_uncached_list_flush_dev( + } + } + ++/* Define route change notification chain. */ ++ATOMIC_NOTIFIER_HEAD(ip6route_chain); /* QCA NSS ECM support */ ++ + static inline const void *choose_neigh_daddr(const struct in6_addr *p, + struct sk_buff *skb, + const void *daddr) +@@ -3865,6 +3868,10 @@ int ip6_route_add(struct fib6_config *cf + return PTR_ERR(rt); + + err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack); ++ if (!err) ++ atomic_notifier_call_chain(&ip6route_chain, ++ RTM_NEWROUTE, rt); ++ + fib6_info_release(rt); + + return err; +@@ -3886,6 +3893,9 @@ static int __ip6_del_rt(struct fib6_info + err = fib6_del(rt, info); + spin_unlock_bh(&table->tb6_lock); + ++ if (!err) ++ atomic_notifier_call_chain(&ip6route_chain, ++ RTM_DELROUTE, rt); + out: + fib6_info_release(rt); + return err; +@@ -6339,6 +6349,20 @@ static int ip6_route_dev_notify(struct n + return NOTIFY_OK; + } + ++/* QCA NSS ECM support - Start */ ++int rt6_register_notifier(struct notifier_block *nb) ++{ ++ return atomic_notifier_chain_register(&ip6route_chain, nb); ++} ++EXPORT_SYMBOL(rt6_register_notifier); ++ ++int rt6_unregister_notifier(struct notifier_block *nb) ++{ ++ return atomic_notifier_chain_unregister(&ip6route_chain, nb); ++} ++EXPORT_SYMBOL(rt6_unregister_notifier); ++/* QCA NSS ECM support - End */ ++ + /* + * /proc + */ +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -1639,6 +1639,7 @@ const char *netdev_cmd_to_name(enum netd + N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO) + N(PRE_CHANGEADDR) N(OFFLOAD_XSTATS_ENABLE) N(OFFLOAD_XSTATS_DISABLE) + N(OFFLOAD_XSTATS_REPORT_USED) N(OFFLOAD_XSTATS_REPORT_DELTA) ++ N(BR_JOIN) N(BR_LEAVE) + } + #undef N + return "UNKNOWN_NETDEV_EVENT"; +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1002,6 +1002,7 @@ void inet6_ifa_finish_destroy(struct ine + + kfree_rcu(ifp, rcu); + } ++EXPORT_SYMBOL(inet6_ifa_finish_destroy); + + static void + ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) +--- a/include/net/vxlan.h ++++ b/include/net/vxlan.h +@@ -432,6 +432,15 @@ static inline __be32 vxlan_compute_rco(u + return vni_field; + } + ++/* ++ * vxlan_get_vni() ++ * Returns the vni corresponding to tunnel ++ */ ++static inline u32 vxlan_get_vni(struct vxlan_dev *vxlan_tun) ++{ ++ return be32_to_cpu(vxlan_tun->cfg.vni); ++} ++ + static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs) + { + return vs->sock->sk->sk_family; +--- a/include/uapi/linux/in.h ++++ b/include/uapi/linux/in.h +@@ -63,6 +63,8 @@ enum { + #define IPPROTO_MTP IPPROTO_MTP + IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */ + #define IPPROTO_BEETPH IPPROTO_BEETPH ++ IPPROTO_ETHERIP = 97, /* ETHERIP protocol number */ ++#define IPPROTO_ETHERIP IPPROTO_ETHERIP + IPPROTO_ENCAP = 98, /* Encapsulation Header */ + #define IPPROTO_ENCAP IPPROTO_ENCAP + IPPROTO_PIM = 103, /* Protocol Independent Multicast */ +@@ -327,7 +329,7 @@ struct sockaddr_in { + #endif + + /* contains the htonl type stuff.. */ +-#include ++#include + + + #endif /* _UAPI_LINUX_IN_H */ +--- a/tools/include/uapi/linux/in.h ++++ b/tools/include/uapi/linux/in.h +@@ -63,6 +63,8 @@ enum { + #define IPPROTO_MTP IPPROTO_MTP + IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */ + #define IPPROTO_BEETPH IPPROTO_BEETPH ++ IPPROTO_ETHERIP = 97, /* ETHERIP protocol number */ ++#define IPPROTO_ETHERIP IPPROTO_ETHERIP + IPPROTO_ENCAP = 98, /* Encapsulation Header */ + #define IPPROTO_ENCAP IPPROTO_ENCAP + IPPROTO_PIM = 103, /* Protocol Independent Multicast */ +@@ -327,7 +329,7 @@ struct sockaddr_in { + #endif + + /* contains the htonl type stuff.. */ +-#include ++#include + + + #endif /* _UAPI_LINUX_IN_H */ +--- a/net/netfilter/nf_conntrack_ecache.c ++++ b/net/netfilter/nf_conntrack_ecache.c +@@ -266,7 +266,6 @@ void nf_conntrack_register_notifier(stru + mutex_lock(&nf_ct_ecache_mutex); + notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb, + lockdep_is_held(&nf_ct_ecache_mutex)); +- WARN_ON_ONCE(notify); + rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new); + mutex_unlock(&nf_ct_ecache_mutex); + } +--- a/include/net/netns/conntrack.h ++++ b/include/net/netns/conntrack.h +@@ -26,6 +26,7 @@ struct nf_tcp_net { + unsigned int timeouts[TCP_CONNTRACK_TIMEOUT_MAX]; + u8 tcp_loose; + u8 tcp_be_liberal; ++ u8 tcp_no_window_check; + u8 tcp_max_retrans; + u8 tcp_ignore_invalid_rst; + #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) +--- a/net/netfilter/nf_conntrack_proto_tcp.c ++++ b/net/netfilter/nf_conntrack_proto_tcp.c +@@ -513,11 +513,15 @@ tcp_in_window(struct nf_conn *ct, enum ip_conntrack_dir dir, + struct ip_ct_tcp *state = &ct->proto.tcp; + struct ip_ct_tcp_state *sender = &state->seen[dir]; + struct ip_ct_tcp_state *receiver = &state->seen[!dir]; ++ const struct nf_tcp_net *tn = nf_tcp_pernet(nf_ct_net(ct)); + __u32 seq, ack, sack, end, win, swin; + bool in_recv_win, seq_ok; + s32 receiver_offset; + u16 win_raw; + ++ if (tn->tcp_no_window_check) ++ return NFCT_TCP_ACCEPT; ++ + /* + * Get the required data from the packet. + */ +@@ -1257,7 +1261,7 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct, + IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && + timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK]) + timeout = timeouts[TCP_CONNTRACK_UNACK]; +- else if (ct->proto.tcp.last_win == 0 && ++ else if (!tn->tcp_no_window_check && ct->proto.tcp.last_win == 0 && + timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS]) + timeout = timeouts[TCP_CONNTRACK_RETRANS]; + else +@@ -1573,6 +1577,9 @@ void nf_conntrack_tcp_init_net(struct net *net) + */ + tn->tcp_be_liberal = 0; + ++ /* Skip Windows Check */ ++ tn->tcp_no_window_check = 0; ++ + /* If it's non-zero, we turn off RST sequence number check */ + tn->tcp_ignore_invalid_rst = 0; + +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -637,6 +637,7 @@ enum nf_ct_sysctl_index { + #endif + NF_SYSCTL_CT_PROTO_TCP_LOOSE, + NF_SYSCTL_CT_PROTO_TCP_LIBERAL, ++ NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK, + NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST, + NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS, + NF_SYSCTL_CT_PROTO_TIMEOUT_UDP, +@@ -844,6 +845,14 @@ static struct ctl_table nf_ct_sysctl_table[] = { + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, ++ [NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK] = { ++ .procname = "nf_conntrack_tcp_no_window_check", ++ .maxlen = sizeof(u8), ++ .mode = 0644, ++ .proc_handler = proc_dou8vec_minmax, ++ .extra1 = SYSCTL_ZERO, ++ .extra2 = SYSCTL_ONE, ++ }, + [NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST] = { + .procname = "nf_conntrack_tcp_ignore_invalid_rst", + .maxlen = sizeof(u8), +@@ -1054,6 +1063,7 @@ static void nf_conntrack_standalone_init_tcp_sysctl(struct net *net, + + XASSIGN(LOOSE, &tn->tcp_loose); + XASSIGN(LIBERAL, &tn->tcp_be_liberal); ++ XASSIGN(NO_WINDOW_CHECK, &tn->tcp_no_window_check); + XASSIGN(MAX_RETRANS, &tn->tcp_max_retrans); + XASSIGN(IGNORE_INVALID_RST, &tn->tcp_ignore_invalid_rst); + #undef XASSIGN diff --git a/6.1/target/linux/qualcommax/patches-6.1/0600-2-qca-nss-ecm-support-PPPOE-offload.patch b/6.1/target/linux/qualcommax/patches-6.1/0600-2-qca-nss-ecm-support-PPPOE-offload.patch new file mode 100644 index 000000000..01c13a341 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0600-2-qca-nss-ecm-support-PPPOE-offload.patch @@ -0,0 +1,600 @@ +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -48,6 +48,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -254,6 +255,25 @@ struct ppp_net { + #define seq_before(a, b) ((s32)((a) - (b)) < 0) + #define seq_after(a, b) ((s32)((a) - (b)) > 0) + ++ ++/* ++ * Registration/Unregistration methods ++ * for PPP channel connect and disconnect event notifications. ++ */ ++RAW_NOTIFIER_HEAD(ppp_channel_connection_notifier_list); ++ ++void ppp_channel_connection_register_notify(struct notifier_block *nb) ++{ ++ raw_notifier_chain_register(&ppp_channel_connection_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(ppp_channel_connection_register_notify); ++ ++void ppp_channel_connection_unregister_notify(struct notifier_block *nb) ++{ ++ raw_notifier_chain_unregister(&ppp_channel_connection_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(ppp_channel_connection_unregister_notify); ++ + /* Prototypes. */ + static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct file *file, unsigned int cmd, unsigned long arg); +@@ -3453,7 +3473,10 @@ ppp_connect_channel(struct channel *pch, + struct ppp_net *pn; + int ret = -ENXIO; + int hdrlen; ++ int ppp_proto; ++ int version; + ++ int notify = 0; + pn = ppp_pernet(pch->chan_net); + + mutex_lock(&pn->all_ppp_mutex); +@@ -3485,13 +3508,40 @@ ppp_connect_channel(struct channel *pch, + ++ppp->n_channels; + pch->ppp = ppp; + refcount_inc(&ppp->file.refcnt); ++ ++ /* Set the netdev priv flag if the prototype ++ * is L2TP or PPTP. Return success in all cases ++ */ ++ if (!pch->chan) ++ goto out2; ++ ++ ppp_proto = ppp_channel_get_protocol(pch->chan); ++ if (ppp_proto == PX_PROTO_PPTP) { ++ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_PPTP; ++ } else if (ppp_proto == PX_PROTO_OL2TP) { ++ version = ppp_channel_get_proto_version(pch->chan); ++ if (version == 2) ++ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_L2TPV2; ++ else if (version == 3) ++ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_L2TPV3; ++ } ++ notify = 1; ++ ++ out2: + ppp_unlock(ppp); + ret = 0; +- + outl: + write_unlock_bh(&pch->upl); + out: + mutex_unlock(&pn->all_ppp_mutex); ++ ++ if (notify && ppp && ppp->dev) { ++ dev_hold(ppp->dev); ++ raw_notifier_call_chain(&ppp_channel_connection_notifier_list, ++ PPP_CHANNEL_CONNECT, ppp->dev); ++ dev_put(ppp->dev); ++ } ++ + return ret; + } + +@@ -3509,6 +3559,13 @@ ppp_disconnect_channel(struct channel *p + pch->ppp = NULL; + write_unlock_bh(&pch->upl); + if (ppp) { ++ if (ppp->dev) { ++ dev_hold(ppp->dev); ++ raw_notifier_call_chain(&ppp_channel_connection_notifier_list, ++ PPP_CHANNEL_DISCONNECT, ppp->dev); ++ dev_put(ppp->dev); ++ } ++ + /* remove it from the ppp unit's list */ + ppp_lock(ppp); + list_del(&pch->clist); +@@ -3588,6 +3645,222 @@ static void *unit_find(struct idr *p, in + return idr_find(p, n); + } + ++/* Updates the PPP interface statistics. */ ++void ppp_update_stats(struct net_device *dev, unsigned long rx_packets, ++ unsigned long rx_bytes, unsigned long tx_packets, ++ unsigned long tx_bytes, unsigned long rx_errors, ++ unsigned long tx_errors, unsigned long rx_dropped, ++ unsigned long tx_dropped) ++{ ++ struct ppp *ppp; ++ ++ if (!dev) ++ return; ++ ++ if (dev->type != ARPHRD_PPP) ++ return; ++ ++ ppp = netdev_priv(dev); ++ ++ ppp_xmit_lock(ppp); ++ ppp->stats64.tx_packets += tx_packets; ++ ppp->stats64.tx_bytes += tx_bytes; ++ ppp->dev->stats.tx_errors += tx_errors; ++ ppp->dev->stats.tx_dropped += tx_dropped; ++ if (tx_packets) ++ ppp->last_xmit = jiffies; ++ ppp_xmit_unlock(ppp); ++ ++ ppp_recv_lock(ppp); ++ ppp->stats64.rx_packets += rx_packets; ++ ppp->stats64.rx_bytes += rx_bytes; ++ ppp->dev->stats.rx_errors += rx_errors; ++ ppp->dev->stats.rx_dropped += rx_dropped; ++ if (rx_packets) ++ ppp->last_recv = jiffies; ++ ppp_recv_unlock(ppp); ++} ++ ++/* Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 if ++ * the device is not PPP. ++ */ ++int ppp_is_multilink(struct net_device *dev) ++{ ++ struct ppp *ppp; ++ unsigned int flags; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ ppp_lock(ppp); ++ flags = ppp->flags; ++ ppp_unlock(ppp); ++ ++ if (flags & SC_MULTILINK) ++ return 1; ++ ++ return 0; ++} ++EXPORT_SYMBOL(ppp_is_multilink); ++ ++/* ppp_channel_get_protocol() ++ * Call this to obtain the underlying protocol of the PPP channel, ++ * e.g. PX_PROTO_OE ++ * ++ * NOTE: Some channels do not use PX sockets so the protocol value may be very ++ * different for them. ++ * NOTE: -1 indicates failure. ++ * NOTE: Once you know the channel protocol you may then either cast 'chan' to ++ * its sub-class or use the channel protocol specific API's as provided by that ++ * channel sub type. ++ */ ++int ppp_channel_get_protocol(struct ppp_channel *chan) ++{ ++ if (!chan->ops->get_channel_protocol) ++ return -1; ++ ++ return chan->ops->get_channel_protocol(chan); ++} ++EXPORT_SYMBOL(ppp_channel_get_protocol); ++ ++/* ppp_channel_get_proto_version() ++ * Call this to get channel protocol version ++ */ ++int ppp_channel_get_proto_version(struct ppp_channel *chan) ++{ ++ if (!chan->ops->get_channel_protocol_ver) ++ return -1; ++ ++ return chan->ops->get_channel_protocol_ver(chan); ++} ++EXPORT_SYMBOL(ppp_channel_get_proto_version); ++ ++/* ppp_channel_hold() ++ * Call this to hold a channel. ++ * ++ * Returns true on success or false if the hold could not happen. ++ * ++ * NOTE: chan must be protected against destruction during this call - ++ * either by correct locking etc. or because you already have an implicit ++ * or explicit hold to the channel already and this is an additional hold. ++ */ ++bool ppp_channel_hold(struct ppp_channel *chan) ++{ ++ if (!chan->ops->hold) ++ return false; ++ ++ chan->ops->hold(chan); ++ return true; ++} ++EXPORT_SYMBOL(ppp_channel_hold); ++ ++/* ppp_channel_release() ++ * Call this to release a hold you have upon a channel ++ */ ++void ppp_channel_release(struct ppp_channel *chan) ++{ ++ chan->ops->release(chan); ++} ++EXPORT_SYMBOL(ppp_channel_release); ++ ++/* Check if ppp xmit lock is on hold */ ++bool ppp_is_xmit_locked(struct net_device *dev) ++{ ++ struct ppp *ppp; ++ ++ if (!dev) ++ return false; ++ ++ if (dev->type != ARPHRD_PPP) ++ return false; ++ ++ ppp = netdev_priv(dev); ++ if (!ppp) ++ return false; ++ ++ if (spin_is_locked(&(ppp)->wlock)) ++ return true; ++ ++ return false; ++} ++EXPORT_SYMBOL(ppp_is_xmit_locked); ++ ++/* ppp_hold_channels() ++ * Returns the PPP channels of the PPP device, storing each one into ++ * channels[]. ++ * ++ * channels[] has chan_sz elements. ++ * This function returns the number of channels stored, up to chan_sz. ++ * It will return < 0 if the device is not PPP. ++ * ++ * You MUST release the channels using ppp_release_channels(). ++ */ ++int ppp_hold_channels(struct net_device *dev, struct ppp_channel *channels[], ++ unsigned int chan_sz) ++{ ++ struct ppp *ppp; ++ int c; ++ struct channel *pch; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ ++ c = 0; ++ ppp_lock(ppp); ++ list_for_each_entry(pch, &ppp->channels, clist) { ++ struct ppp_channel *chan; ++ ++ if (!pch->chan) { ++ /* Channel is going / gone away */ ++ continue; ++ } ++ ++ if (c == chan_sz) { ++ /* No space to record channel */ ++ ppp_unlock(ppp); ++ return c; ++ } ++ ++ /* Hold the channel, if supported */ ++ chan = pch->chan; ++ if (!chan->ops->hold) ++ continue; ++ ++ chan->ops->hold(chan); ++ ++ /* Record the channel */ ++ channels[c++] = chan; ++ } ++ ppp_unlock(ppp); ++ return c; ++} ++EXPORT_SYMBOL(ppp_hold_channels); ++ ++/* ppp_release_channels() ++ * Releases channels ++ */ ++void ppp_release_channels(struct ppp_channel *channels[], unsigned int chan_sz) ++{ ++ unsigned int c; ++ ++ for (c = 0; c < chan_sz; ++c) { ++ struct ppp_channel *chan; ++ ++ chan = channels[c]; ++ chan->ops->release(chan); ++ } ++} ++EXPORT_SYMBOL(ppp_release_channels); ++ + /* Module/initialization stuff */ + + module_init(ppp_init); +@@ -3604,6 +3877,7 @@ EXPORT_SYMBOL(ppp_input_error); + EXPORT_SYMBOL(ppp_output_wakeup); + EXPORT_SYMBOL(ppp_register_compressor); + EXPORT_SYMBOL(ppp_unregister_compressor); ++EXPORT_SYMBOL(ppp_update_stats); + MODULE_LICENSE("GPL"); + MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0); + MODULE_ALIAS_RTNL_LINK("ppp"); +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -62,6 +62,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -87,7 +88,7 @@ + static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb); + + static const struct proto_ops pppoe_ops; +-static const struct ppp_channel_ops pppoe_chan_ops; ++static const struct pppoe_channel_ops pppoe_chan_ops; + + /* per-net private data for this module */ + static unsigned int pppoe_net_id __read_mostly; +@@ -692,7 +693,7 @@ static int pppoe_connect(struct socket * + + po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2; + po->chan.private = sk; +- po->chan.ops = &pppoe_chan_ops; ++ po->chan.ops = (struct ppp_channel_ops *)&pppoe_chan_ops; + + error = ppp_register_net_channel(dev_net(dev), &po->chan); + if (error) { +@@ -995,9 +996,80 @@ static int pppoe_fill_forward_path(struc + return 0; + } + +-static const struct ppp_channel_ops pppoe_chan_ops = { +- .start_xmit = pppoe_xmit, +- .fill_forward_path = pppoe_fill_forward_path, ++/************************************************************************ ++ * ++ * function called by generic PPP driver to hold channel ++ * ++ ***********************************************************************/ ++static void pppoe_hold_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_hold(sk); ++} ++ ++/************************************************************************ ++ * ++ * function called by generic PPP driver to release channel ++ * ++ ***********************************************************************/ ++static void pppoe_release_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_put(sk); ++} ++ ++/************************************************************************ ++ * ++ * function called to get the channel protocol type ++ * ++ ***********************************************************************/ ++static int pppoe_get_channel_protocol(struct ppp_channel *chan) ++{ ++ return PX_PROTO_OE; ++} ++ ++/************************************************************************ ++ * ++ * function called to get the PPPoE channel addressing ++ * NOTE: This function returns a HOLD to the netdevice ++ * ++ ***********************************************************************/ ++static int pppoe_get_addressing(struct ppp_channel *chan, ++ struct pppoe_opt *addressing) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ struct pppox_sock *po = pppox_sk(sk); ++ int err = 0; ++ ++ *addressing = po->proto.pppoe; ++ if (!addressing->dev) ++ return -ENODEV; ++ ++ dev_hold(addressing->dev); ++ return err; ++} ++ ++/* pppoe_channel_addressing_get() ++ * Return PPPoE channel specific addressing information. ++ */ ++int pppoe_channel_addressing_get(struct ppp_channel *chan, ++ struct pppoe_opt *addressing) ++{ ++ return pppoe_get_addressing(chan, addressing); ++} ++EXPORT_SYMBOL(pppoe_channel_addressing_get); ++ ++static const struct pppoe_channel_ops pppoe_chan_ops = { ++ /* PPPoE specific channel ops */ ++ .get_addressing = pppoe_get_addressing, ++ /* General ppp channel ops */ ++ .ops.start_xmit = pppoe_xmit, ++ .ops.get_channel_protocol = pppoe_get_channel_protocol, ++ .ops.hold = pppoe_hold_chan, ++ .ops.release = pppoe_release_chan, ++ .ops.fill_forward_path = pppoe_fill_forward_path, + }; + + static int pppoe_recvmsg(struct socket *sock, struct msghdr *m, +--- a/include/linux/if_pppox.h ++++ b/include/linux/if_pppox.h +@@ -91,4 +91,17 @@ enum { + PPPOX_DEAD = 16 /* dead, useless, please clean me up!*/ + }; + ++/* ++ * PPPoE Channel specific operations ++ */ ++struct pppoe_channel_ops { ++ /* Must be first - general to all PPP channels */ ++ struct ppp_channel_ops ops; ++ int (*get_addressing)(struct ppp_channel *, struct pppoe_opt *); ++}; ++ ++/* Return PPPoE channel specific addressing information */ ++extern int pppoe_channel_addressing_get(struct ppp_channel *chan, ++ struct pppoe_opt *addressing); ++ + #endif /* !(__LINUX_IF_PPPOX_H) */ +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1762,6 +1762,36 @@ enum netdev_priv_flags { + IFF_NO_IP_ALIGN = BIT_ULL(34), + }; + ++/** ++ * enum netdev_priv_flags_ext - &struct net_device priv_flags_ext ++ * ++ * These flags are used to check for device type and can be ++ * set and used by the drivers ++ * ++ * @IFF_EXT_TUN_TAP: device is a TUN/TAP device ++ * @IFF_EXT_PPP_L2TPV2: device is a L2TPV2 device ++ * @IFF_EXT_PPP_L2TPV3: device is a L2TPV3 device ++ * @IFF_EXT_PPP_PPTP: device is a PPTP device ++ * @IFF_EXT_GRE_V4_TAP: device is a GRE IPv4 TAP device ++ * @IFF_EXT_GRE_V6_TAP: device is a GRE IPv6 TAP device ++ * @IFF_EXT_IFB: device is an IFB device ++ * @IFF_EXT_MAPT: device is an MAPT device ++ * @IFF_EXT_HW_NO_OFFLOAD: device is an NON Offload device ++ * @IFF_EXT_L2TPV3: device is a L2TPV3 Ethernet device ++ */ ++enum netdev_priv_flags_ext { ++ IFF_EXT_TUN_TAP = 1<<0, ++ IFF_EXT_PPP_L2TPV2 = 1<<1, ++ IFF_EXT_PPP_L2TPV3 = 1<<2, ++ IFF_EXT_PPP_PPTP = 1<<3, ++ IFF_EXT_GRE_V4_TAP = 1<<4, ++ IFF_EXT_GRE_V6_TAP = 1<<5, ++ IFF_EXT_IFB = 1<<6, ++ IFF_EXT_MAPT = 1<<7, ++ IFF_EXT_HW_NO_OFFLOAD = 1<<8, ++ IFF_EXT_ETH_L2TPV3 = 1<<9, ++}; ++ + #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN + #define IFF_EBRIDGE IFF_EBRIDGE + #define IFF_BONDING IFF_BONDING +@@ -2075,6 +2103,7 @@ struct net_device { + /* Read-mostly cache-line for fast-path access */ + unsigned int flags; + unsigned long long priv_flags; ++ unsigned int priv_flags_ext; + const struct net_device_ops *netdev_ops; + int ifindex; + unsigned short gflags; +--- a/include/linux/ppp_channel.h ++++ b/include/linux/ppp_channel.h +@@ -19,6 +19,10 @@ + #include + #include + #include ++#include ++ ++#define PPP_CHANNEL_DISCONNECT 0 ++#define PPP_CHANNEL_CONNECT 1 + + struct net_device_path; + struct net_device_path_ctx; +@@ -30,9 +34,19 @@ struct ppp_channel_ops { + int (*start_xmit)(struct ppp_channel *, struct sk_buff *); + /* Handle an ioctl call that has come in via /dev/ppp. */ + int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long); ++ /* Get channel protocol type, one of PX_PROTO_XYZ or specific to ++ * the channel subtype ++ */ ++ int (*get_channel_protocol)(struct ppp_channel *); ++ /* Get channel protocol version */ ++ int (*get_channel_protocol_ver)(struct ppp_channel *); ++ /* Hold the channel from being destroyed */ ++ void (*hold)(struct ppp_channel *); ++ /* Release hold on the channel */ ++ void (*release)(struct ppp_channel *); + int (*fill_forward_path)(struct net_device_path_ctx *, +- struct net_device_path *, +- const struct ppp_channel *); ++ struct net_device_path *, ++ const struct ppp_channel *); + }; + + struct ppp_channel { +@@ -76,6 +90,51 @@ extern int ppp_unit_number(struct ppp_ch + /* Get the device name associated with a channel, or NULL if none */ + extern char *ppp_dev_name(struct ppp_channel *); + ++/* Call this to obtain the underlying protocol of the PPP channel, ++ * e.g. PX_PROTO_OE ++ */ ++extern int ppp_channel_get_protocol(struct ppp_channel *); ++ ++/* Call this get protocol version */ ++extern int ppp_channel_get_proto_version(struct ppp_channel *); ++ ++/* Call this to hold a channel */ ++extern bool ppp_channel_hold(struct ppp_channel *); ++ ++/* Call this to release a hold you have upon a channel */ ++extern void ppp_channel_release(struct ppp_channel *); ++ ++/* Release hold on PPP channels */ ++extern void ppp_release_channels(struct ppp_channel *channels[], ++ unsigned int chan_sz); ++ ++/* Hold PPP channels for the PPP device */ ++extern int ppp_hold_channels(struct net_device *dev, ++ struct ppp_channel *channels[], ++ unsigned int chan_sz); ++ ++/* Test if ppp xmit lock is locked */ ++extern bool ppp_is_xmit_locked(struct net_device *dev); ++ ++/* Test if the ppp device is a multi-link ppp device */ ++extern int ppp_is_multilink(struct net_device *dev); ++ ++/* Register the PPP channel connect notifier */ ++extern void ppp_channel_connection_register_notify(struct notifier_block *nb); ++ ++/* Unregister the PPP channel connect notifier */ ++extern void ppp_channel_connection_unregister_notify(struct notifier_block *nb); ++ ++/* Update statistics of the PPP net_device by incrementing related ++ * statistics field value with corresponding parameter ++ */ ++extern void ppp_update_stats(struct net_device *dev, unsigned long rx_packets, ++ unsigned long rx_bytes, unsigned long tx_packets, ++ unsigned long tx_bytes, unsigned long rx_errors, ++ unsigned long tx_errors, unsigned long rx_dropped, ++ unsigned long tx_dropped); ++ ++ + /* + * SMP locking notes: + * The channel code must ensure that when it calls ppp_unregister_channel, diff --git a/6.1/target/linux/qualcommax/patches-6.1/0600-3-qca-nss-ecm-support-net-bonding.patch b/6.1/target/linux/qualcommax/patches-6.1/0600-3-qca-nss-ecm-support-net-bonding.patch new file mode 100644 index 000000000..f2cb4f3a9 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0600-3-qca-nss-ecm-support-net-bonding.patch @@ -0,0 +1,49 @@ +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -208,6 +208,7 @@ atomic_t netpoll_block_tx = ATOMIC_INIT( + #endif + + unsigned int bond_net_id __read_mostly; ++static unsigned long bond_id_mask = 0xFFFFFFF0; /* QCA NSS ECM bonding support */ + + static const struct flow_dissector_key flow_keys_bonding_keys[] = { + { +@@ -5793,8 +5794,14 @@ static void bond_destructor(struct net_d + if (bond->wq) + destroy_workqueue(bond->wq); + ++ /* QCA NSS ECM bonding support - Start */ ++ if (bond->id != (~0U)) ++ clear_bit(bond->id, &bond_id_mask); ++ /* QCA NSS ECM bonding support - End */ ++ + if (bond->rr_tx_counter) + free_percpu(bond->rr_tx_counter); ++ + } + + void bond_setup(struct net_device *bond_dev) +@@ -6358,6 +6365,13 @@ int bond_create(struct net *net, const c + + bond_work_init_all(bond); + ++ /* QCA NSS ECM bonding support - Start */ ++ bond->id = ~0U; ++ if (bond_id_mask != (~0UL)) { ++ bond->id = (u32)ffz(bond_id_mask); ++ set_bit(bond->id, &bond_id_mask); ++ } ++ /* QCA NSS ECM bonding support - End */ + out: + rtnl_unlock(); + return res; +--- a/include/net/bonding.h ++++ b/include/net/bonding.h +@@ -265,6 +265,7 @@ struct bonding { + spinlock_t ipsec_lock; + #endif /* CONFIG_XFRM_OFFLOAD */ + struct bpf_prog *xdp_prog; ++ u32 id;/* QCA NSS ECM bonding support */ + }; + + #define bond_slave_get_rcu(dev) \ diff --git a/6.1/target/linux/qualcommax/patches-6.1/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch b/6.1/target/linux/qualcommax/patches-6.1/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch new file mode 100644 index 000000000..0548b17c8 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch @@ -0,0 +1,685 @@ +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -115,6 +115,40 @@ static void ad_marker_response_received( + struct port *port); + static void ad_update_actor_keys(struct port *port, bool reset); + ++/* QCA NSS ECM bonding support - Start */ ++struct bond_cb __rcu *bond_cb; ++ ++int bond_register_cb(struct bond_cb *cb) ++{ ++ struct bond_cb *lag_cb; ++ ++ lag_cb = kzalloc(sizeof(*lag_cb), GFP_ATOMIC | __GFP_NOWARN); ++ if (!lag_cb) { ++ return -1; ++ } ++ ++ memcpy((void *)lag_cb, (void *)cb, sizeof(*cb)); ++ ++ rcu_read_lock(); ++ rcu_assign_pointer(bond_cb, lag_cb); ++ rcu_read_unlock(); ++ return 0; ++} ++EXPORT_SYMBOL(bond_register_cb); ++ ++void bond_unregister_cb(void) ++{ ++ struct bond_cb *lag_cb_main; ++ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ rcu_assign_pointer(bond_cb, NULL); ++ rcu_read_unlock(); ++ ++ kfree(lag_cb_main); ++} ++EXPORT_SYMBOL(bond_unregister_cb); ++/* QCA NSS ECM bonding support - End */ + + /* ================= api to bonding and kernel code ================== */ + +@@ -1064,7 +1098,31 @@ static void ad_mux_machine(struct port * + ad_disable_collecting_distributing(port, + update_slave_arr); + port->ntt = true; ++ ++ /* QCA NSS ECM bonding support - Start */ ++ /* Send a notificaton about change in state of this ++ * port. We only want to handle case where port moves ++ * from AD_MUX_COLLECTING_DISTRIBUTING -> ++ * AD_MUX_ATTACHED. ++ */ ++ if (bond_slave_is_up(port->slave) && ++ (last_state == AD_MUX_COLLECTING_DISTRIBUTING)) { ++ struct bond_cb *lag_cb_main; ++ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ if (lag_cb_main && ++ lag_cb_main->bond_cb_link_down) { ++ struct net_device *dev; ++ ++ dev = port->slave->dev; ++ lag_cb_main->bond_cb_link_down(dev); ++ } ++ rcu_read_unlock(); ++ } ++ + break; ++ /* QCA NSS ECM bonding support - End */ + case AD_MUX_COLLECTING_DISTRIBUTING: + port->actor_oper_port_state |= LACP_STATE_COLLECTING; + port->actor_oper_port_state |= LACP_STATE_DISTRIBUTING; +@@ -1908,6 +1966,7 @@ static void ad_enable_collecting_distrib + bool *update_slave_arr) + { + if (port->aggregator->is_active) { ++ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */ + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Enabling port %d (LAG %d)\n", + port->actor_port_number, +@@ -1915,6 +1974,16 @@ static void ad_enable_collecting_distrib + __enable_port(port); + /* Slave array needs update */ + *update_slave_arr = true; ++ ++ /* QCA NSS ECM bonding support - Start */ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ ++ if (lag_cb_main && lag_cb_main->bond_cb_link_up) ++ lag_cb_main->bond_cb_link_up(port->slave->dev); ++ ++ rcu_read_unlock(); ++ /* QCA NSS ECM bonding support - End */ + } + } + +@@ -2674,6 +2743,104 @@ int bond_3ad_get_active_agg_info(struct + return ret; + } + ++/* QCA NSS ECM bonding support - Start */ ++/* bond_3ad_get_tx_dev - Calculate egress interface for a given packet, ++ * for a LAG that is configured in 802.3AD mode ++ * @skb: pointer to skb to be egressed ++ * @src_mac: pointer to source L2 address ++ * @dst_mac: pointer to destination L2 address ++ * @src: pointer to source L3 address ++ * @dst: pointer to destination L3 address ++ * @protocol: L3 protocol id from L2 header ++ * @bond_dev: pointer to bond master device ++ * ++ * If @skb is NULL, bond_xmit_hash is used to calculate hash using L2/L3 ++ * addresses. ++ * ++ * Returns: Either valid slave device, or NULL otherwise ++ */ ++struct net_device *bond_3ad_get_tx_dev(struct sk_buff *skb, u8 *src_mac, ++ u8 *dst_mac, void *src, ++ void *dst, u16 protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr) ++{ ++ struct bonding *bond = netdev_priv(bond_dev); ++ struct aggregator *agg; ++ struct ad_info ad_info; ++ struct list_head *iter; ++ struct slave *slave; ++ struct slave *first_ok_slave = NULL; ++ u32 hash = 0; ++ int slaves_in_agg; ++ int slave_agg_no = 0; ++ int agg_id; ++ ++ if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { ++ pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n", ++ bond_dev->name); ++ return NULL; ++ } ++ ++ slaves_in_agg = ad_info.ports; ++ agg_id = ad_info.aggregator_id; ++ ++ if (slaves_in_agg == 0) { ++ pr_debug("%s: Error: active aggregator is empty\n", ++ bond_dev->name); ++ return NULL; ++ } ++ ++ if (skb) { ++ hash = bond_xmit_hash(bond, skb); ++ slave_agg_no = hash % slaves_in_agg; ++ } else { ++ if (bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER23 && ++ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER2 && ++ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER34) { ++ pr_debug("%s: Error: Unsupported hash policy for 802.3AD fast path\n", ++ bond_dev->name); ++ return NULL; ++ } ++ ++ hash = bond_xmit_hash_without_skb(src_mac, dst_mac, ++ src, dst, protocol, ++ bond_dev, layer4hdr); ++ slave_agg_no = hash % slaves_in_agg; ++ } ++ ++ bond_for_each_slave_rcu(bond, slave, iter) { ++ agg = SLAVE_AD_INFO(slave)->port.aggregator; ++ if (!agg || agg->aggregator_identifier != agg_id) ++ continue; ++ ++ if (slave_agg_no >= 0) { ++ if (!first_ok_slave && bond_slave_can_tx(slave)) ++ first_ok_slave = slave; ++ slave_agg_no--; ++ continue; ++ } ++ ++ if (bond_slave_can_tx(slave)) ++ return slave->dev; ++ } ++ ++ if (slave_agg_no >= 0) { ++ pr_err("%s: Error: Couldn't find a slave to tx on for aggregator ID %d\n", ++ bond_dev->name, agg_id); ++ return NULL; ++ } ++ ++ /* we couldn't find any suitable slave after the agg_no, so use the ++ * first suitable found, if found. ++ */ ++ if (first_ok_slave) ++ return first_ok_slave->dev; ++ ++ return NULL; ++} ++/* QCA NSS ECM bonding support - End */ ++ + int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond, + struct slave *slave) + { +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -286,6 +286,21 @@ const char *bond_mode_name(int mode) + return names[mode]; + } + ++/* QCA NSS ECM bonding support */ ++int bond_get_id(struct net_device *bond_dev) ++{ ++ struct bonding *bond; ++ ++ if (!((bond_dev->priv_flags & IFF_BONDING) && ++ (bond_dev->flags & IFF_MASTER))) ++ return -EINVAL; ++ ++ bond = netdev_priv(bond_dev); ++ return bond->id; ++} ++EXPORT_SYMBOL(bond_get_id); ++/* QCA NSS ECM bonding support */ ++ + /** + * bond_dev_queue_xmit - Prepare skb for xmit. + * +@@ -1185,6 +1200,23 @@ void bond_change_active_slave(struct bon + if (BOND_MODE(bond) == BOND_MODE_8023AD) + bond_3ad_handle_link_change(new_active, BOND_LINK_UP); + ++ /* QCA NSS ECM bonding support - Start */ ++ if (bond->params.mode == BOND_MODE_XOR) { ++ struct bond_cb *lag_cb_main; ++ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ if (lag_cb_main && ++ lag_cb_main->bond_cb_link_up) { ++ struct net_device *dev; ++ ++ dev = new_active->dev; ++ lag_cb_main->bond_cb_link_up(dev); ++ } ++ rcu_read_unlock(); ++ } ++ /* QCA NSS ECM bonding support - End */ ++ + if (bond_is_lb(bond)) + bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); + } else { +@@ -1808,6 +1840,7 @@ int bond_enslave(struct net_device *bond + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; + struct slave *new_slave = NULL, *prev_slave; + struct sockaddr_storage ss; ++ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */ + int link_reporting; + int res = 0, i; + +@@ -2251,6 +2284,15 @@ int bond_enslave(struct net_device *bond + bond_is_active_slave(new_slave) ? "an active" : "a backup", + new_slave->link != BOND_LINK_DOWN ? "an up" : "a down"); + ++ /* QCA NSS ECM bonding support - Start */ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ if (lag_cb_main && lag_cb_main->bond_cb_enslave) ++ lag_cb_main->bond_cb_enslave(slave_dev); ++ ++ rcu_read_unlock(); ++ /* QCA NSS ECM bonding support - End */ ++ + /* enslave is successful */ + bond_queue_slave_event(new_slave); + return 0; +@@ -2316,6 +2358,15 @@ err_undo_flags: + } + } + ++ /* QCA NSS ECM bonding support - Start */ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ if (lag_cb_main && lag_cb_main->bond_cb_enslave) ++ lag_cb_main->bond_cb_enslave(slave_dev); ++ ++ rcu_read_unlock(); ++ /* QCA NSS ECM bonding support - End */ ++ + return res; + } + +@@ -2337,6 +2388,7 @@ static int __bond_release_one(struct net + struct bonding *bond = netdev_priv(bond_dev); + struct slave *slave, *oldcurrent; + struct sockaddr_storage ss; ++ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */ + int old_flags = bond_dev->flags; + netdev_features_t old_features = bond_dev->features; + +@@ -2359,6 +2411,15 @@ static int __bond_release_one(struct net + + bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW); + ++ /* QCA NSS ECM bonding support - Start */ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ if (lag_cb_main && lag_cb_main->bond_cb_release) ++ lag_cb_main->bond_cb_release(slave_dev); ++ ++ rcu_read_unlock(); ++ /* QCA NSS ECM bonding support - End */ ++ + bond_sysfs_slave_del(slave); + + /* recompute stats just before removing the slave */ +@@ -2678,6 +2739,8 @@ static void bond_miimon_commit(struct bo + struct slave *slave, *primary, *active; + bool do_failover = false; + struct list_head *iter; ++ struct net_device *slave_dev = NULL; /* QCA NSS ECM bonding support */ ++ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */ + + ASSERT_RTNL(); + +@@ -2717,6 +2780,12 @@ static void bond_miimon_commit(struct bo + bond_set_active_slave(slave); + } + ++ /* QCA NSS ECM bonding support - Start */ ++ if ((bond->params.mode == BOND_MODE_XOR) && ++ (!slave_dev)) ++ slave_dev = slave->dev; ++ /* QCA NSS ECM bonding support - End */ ++ + slave_info(bond->dev, slave->dev, "link status definitely up, %u Mbps %s duplex\n", + slave->speed == SPEED_UNKNOWN ? 0 : slave->speed, + slave->duplex ? "full" : "half"); +@@ -2765,6 +2834,16 @@ static void bond_miimon_commit(struct bo + unblock_netpoll_tx(); + } + ++ /* QCA NSS ECM bonding support - Start */ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ ++ if (slave_dev && lag_cb_main && lag_cb_main->bond_cb_link_up) ++ lag_cb_main->bond_cb_link_up(slave_dev); ++ ++ rcu_read_unlock(); ++ /* QCA NSS ECM bonding support - End */ ++ + bond_set_carrier(bond); + } + +@@ -4012,8 +4091,219 @@ static inline u32 bond_eth_hash(struct s + return 0; + + ep = (struct ethhdr *)(data + mhoff); +- return ep->h_dest[5] ^ ep->h_source[5] ^ be16_to_cpu(ep->h_proto); ++ return ep->h_dest[5] ^ ep->h_source[5]; /* QCA NSS ECM bonding support */ ++} ++ ++/* QCA NSS ECM bonding support - Start */ ++/* Extract the appropriate headers based on bond's xmit policy */ ++static bool bond_flow_dissect_without_skb(struct bonding *bond, ++ u8 *src_mac, u8 *dst_mac, ++ void *psrc, void *pdst, ++ u16 protocol, __be16 *layer4hdr, ++ struct flow_keys *fk) ++{ ++ u32 *src = NULL; ++ u32 *dst = NULL; ++ ++ fk->ports.ports = 0; ++ src = (uint32_t *)psrc; ++ dst = (uint32_t *)pdst; ++ ++ if (protocol == htons(ETH_P_IP)) { ++ /* V4 addresses and address type*/ ++ fk->addrs.v4addrs.src = src[0]; ++ fk->addrs.v4addrs.dst = dst[0]; ++ fk->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; ++ } else if (protocol == htons(ETH_P_IPV6)) { ++ /* V6 addresses and address type*/ ++ memcpy(&fk->addrs.v6addrs.src, src, sizeof(struct in6_addr)); ++ memcpy(&fk->addrs.v6addrs.dst, dst, sizeof(struct in6_addr)); ++ fk->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; ++ } else { ++ return false; ++ } ++ if ((bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34) && ++ (layer4hdr)) ++ fk->ports.ports = *layer4hdr; ++ ++ return true; ++} ++ ++/* bond_xmit_hash_without_skb - Applies load balancing algorithm for a packet, ++ * to calculate hash for a given set of L2/L3 addresses. Does not ++ * calculate egress interface. ++ */ ++uint32_t bond_xmit_hash_without_skb(u8 *src_mac, u8 *dst_mac, ++ void *psrc, void *pdst, u16 protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr) ++{ ++ struct bonding *bond = netdev_priv(bond_dev); ++ struct flow_keys flow; ++ u32 hash = 0; ++ ++ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER2 || ++ !bond_flow_dissect_without_skb(bond, src_mac, dst_mac, psrc, ++ pdst, protocol, layer4hdr, &flow)) ++ return (dst_mac[5] ^ src_mac[5]); ++ ++ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23) ++ hash = dst_mac[5] ^ src_mac[5]; ++ else if (layer4hdr) ++ hash = (__force u32)flow.ports.ports; ++ ++ hash ^= (__force u32)flow_get_u32_dst(&flow) ^ ++ (__force u32)flow_get_u32_src(&flow); ++ hash ^= (hash >> 16); ++ hash ^= (hash >> 8); ++ ++ return hash; ++} ++ ++/* bond_xor_get_tx_dev - Calculate egress interface for a given packet for a LAG ++ * that is configured in balance-xor mode ++ * @skb: pointer to skb to be egressed ++ * @src_mac: pointer to source L2 address ++ * @dst_mac: pointer to destination L2 address ++ * @src: pointer to source L3 address in network order ++ * @dst: pointer to destination L3 address in network order ++ * @protocol: L3 protocol ++ * @bond_dev: pointer to bond master device ++ * ++ * If @skb is NULL, bond_xmit_hash_without_skb is used to calculate hash using ++ * L2/L3 addresses. ++ * ++ * Returns: Either valid slave device, or NULL otherwise ++ */ ++static struct net_device *bond_xor_get_tx_dev(struct sk_buff *skb, ++ u8 *src_mac, u8 *dst_mac, ++ void *src, void *dst, ++ u16 protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr) ++{ ++ struct bonding *bond = netdev_priv(bond_dev); ++ int slave_cnt = READ_ONCE(bond->slave_cnt); ++ int slave_id = 0, i = 0; ++ u32 hash; ++ struct list_head *iter; ++ struct slave *slave; ++ ++ if (slave_cnt == 0) { ++ pr_debug("%s: Error: No slave is attached to the interface\n", ++ bond_dev->name); ++ return NULL; ++ } ++ ++ if (skb) { ++ hash = bond_xmit_hash(bond, skb); ++ slave_id = hash % slave_cnt; ++ } else { ++ if (bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER23 && ++ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER2 && ++ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER34) { ++ pr_debug("%s: Error: Unsupported hash policy for balance-XOR fast path\n", ++ bond_dev->name); ++ return NULL; ++ } ++ ++ hash = bond_xmit_hash_without_skb(src_mac, dst_mac, src, ++ dst, protocol, bond_dev, ++ layer4hdr); ++ slave_id = hash % slave_cnt; ++ } ++ ++ i = slave_id; ++ ++ /* Here we start from the slave with slave_id */ ++ bond_for_each_slave_rcu(bond, slave, iter) { ++ if (--i < 0) { ++ if (bond_slave_can_tx(slave)) ++ return slave->dev; ++ } ++ } ++ ++ /* Here we start from the first slave up to slave_id */ ++ i = slave_id; ++ bond_for_each_slave_rcu(bond, slave, iter) { ++ if (--i < 0) ++ break; ++ if (bond_slave_can_tx(slave)) ++ return slave->dev; ++ } ++ ++ return NULL; ++} ++ ++/* bond_get_tx_dev - Calculate egress interface for a given packet. ++ * ++ * Supports 802.3AD and balance-xor modes ++ * ++ * @skb: pointer to skb to be egressed, if valid ++ * @src_mac: pointer to source L2 address ++ * @dst_mac: pointer to destination L2 address ++ * @src: pointer to source L3 address in network order ++ * @dst: pointer to destination L3 address in network order ++ * @protocol: L3 protocol id from L2 header ++ * @bond_dev: pointer to bond master device ++ * ++ * Returns: Either valid slave device, or NULL for un-supported LAG modes ++ */ ++struct net_device *bond_get_tx_dev(struct sk_buff *skb, uint8_t *src_mac, ++ u8 *dst_mac, void *src, ++ void *dst, u16 protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr) ++{ ++ struct bonding *bond; ++ ++ if (!bond_dev) ++ return NULL; ++ ++ if (!((bond_dev->priv_flags & IFF_BONDING) && ++ (bond_dev->flags & IFF_MASTER))) ++ return NULL; ++ ++ bond = netdev_priv(bond_dev); ++ ++ switch (bond->params.mode) { ++ case BOND_MODE_XOR: ++ return bond_xor_get_tx_dev(skb, src_mac, dst_mac, ++ src, dst, protocol, ++ bond_dev, layer4hdr); ++ case BOND_MODE_8023AD: ++ return bond_3ad_get_tx_dev(skb, src_mac, dst_mac, ++ src, dst, protocol, ++ bond_dev, layer4hdr); ++ default: ++ return NULL; ++ } + } ++EXPORT_SYMBOL(bond_get_tx_dev); ++ ++/* In bond_xmit_xor() , we determine the output device by using a pre- ++ * determined xmit_hash_policy(), If the selected device is not enabled, ++ * find the next active slave. ++ */ ++static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct bonding *bond = netdev_priv(dev); ++ struct net_device *outdev; ++ ++ outdev = bond_xor_get_tx_dev(skb, NULL, NULL, NULL, ++ NULL, 0, dev, NULL); ++ if (!outdev) ++ goto out; ++ ++ bond_dev_queue_xmit(bond, skb, outdev); ++ goto final; ++out: ++ /* no suitable interface, frame not sent */ ++ dev_kfree_skb(skb); ++final: ++ return NETDEV_TX_OK; ++} ++/* QCA NSS ECM bonding support - End */ + + static bool bond_flow_ip(struct sk_buff *skb, struct flow_keys *fk, const void *data, + int hlen, __be16 l2_proto, int *nhoff, int *ip_proto, bool l34) +@@ -5192,15 +5482,18 @@ static netdev_tx_t bond_3ad_xor_xmit(str + struct net_device *dev) + { + struct bonding *bond = netdev_priv(dev); +- struct bond_up_slave *slaves; +- struct slave *slave; ++ /* QCA NSS ECM bonding support - Start */ ++ struct net_device *outdev = NULL; + +- slaves = rcu_dereference(bond->usable_slaves); +- slave = bond_xmit_3ad_xor_slave_get(bond, skb, slaves); +- if (likely(slave)) +- return bond_dev_queue_xmit(bond, skb, slave->dev); ++ outdev = bond_3ad_get_tx_dev(skb, NULL, NULL, NULL, ++ NULL, 0, dev, NULL); ++ if (!outdev) { ++ dev_kfree_skb(skb); ++ return NETDEV_TX_OK; ++ } + +- return bond_tx_drop(dev, skb); ++ return bond_dev_queue_xmit(bond, skb, outdev); ++ /* QCA NSS ECM bonding support - End */ + } + + /* in broadcast mode, we send everything to all usable interfaces. */ +@@ -5450,8 +5743,9 @@ static netdev_tx_t __bond_start_xmit(str + return bond_xmit_roundrobin(skb, dev); + case BOND_MODE_ACTIVEBACKUP: + return bond_xmit_activebackup(skb, dev); +- case BOND_MODE_8023AD: + case BOND_MODE_XOR: ++ return bond_xmit_xor(skb, dev); /* QCA NSS ECM bonding support */ ++ case BOND_MODE_8023AD: + return bond_3ad_xor_xmit(skb, dev); + case BOND_MODE_BROADCAST: + return bond_xmit_broadcast(skb, dev); +--- a/include/net/bond_3ad.h ++++ b/include/net/bond_3ad.h +@@ -303,8 +303,15 @@ int bond_3ad_lacpdu_recv(const struct sk + int bond_3ad_set_carrier(struct bonding *bond); + void bond_3ad_update_lacp_active(struct bonding *bond); + void bond_3ad_update_lacp_rate(struct bonding *bond); ++/* QCA NSS ECM bonding support */ ++struct net_device *bond_3ad_get_tx_dev(struct sk_buff *skb, uint8_t *src_mac, ++ uint8_t *dst_mac, void *src, ++ void *dst, uint16_t protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr); ++/* QCA NSS ECM bonding support */ ++ + void bond_3ad_update_ad_actor_settings(struct bonding *bond); + int bond_3ad_stats_fill(struct sk_buff *skb, struct bond_3ad_stats *stats); + size_t bond_3ad_stats_size(void); + #endif /* _NET_BOND_3AD_H */ +- +--- a/include/net/bonding.h ++++ b/include/net/bonding.h +@@ -94,6 +94,8 @@ + + #define BOND_TLS_FEATURES (NETIF_F_HW_TLS_TX | NETIF_F_HW_TLS_RX) + ++extern struct bond_cb __rcu *bond_cb; /* QCA NSS ECM bonding support */ ++ + #ifdef CONFIG_NET_POLL_CONTROLLER + extern atomic_t netpoll_block_tx; + +@@ -659,6 +661,7 @@ struct bond_net { + + int bond_rcv_validate(const struct sk_buff *skb, struct bonding *bond, struct slave *slave); + netdev_tx_t bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); ++int bond_get_id(struct net_device *bond_dev); /* QCA NSS ECM bonding support */ + int bond_create(struct net *net, const char *name); + int bond_create_sysfs(struct bond_net *net); + void bond_destroy_sysfs(struct bond_net *net); +@@ -689,6 +692,13 @@ struct bond_vlan_tag *bond_verify_device + int level); + int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave); + void bond_slave_arr_work_rearm(struct bonding *bond, unsigned long delay); ++/* QCA NSS ECM bonding support - Start */ ++uint32_t bond_xmit_hash_without_skb(uint8_t *src_mac, uint8_t *dst_mac, ++ void *psrc, void *pdst, uint16_t protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr); ++/* QCA NSS ECM bonding support - End */ ++ + void bond_work_init_all(struct bonding *bond); + + #ifdef CONFIG_PROC_FS +@@ -793,4 +803,18 @@ static inline netdev_tx_t bond_tx_drop(s + return NET_XMIT_DROP; + } + ++/* QCA NSS ECM bonding support - Start */ ++struct bond_cb { ++ void (*bond_cb_link_up)(struct net_device *slave); ++ void (*bond_cb_link_down)(struct net_device *slave); ++ void (*bond_cb_enslave)(struct net_device *slave); ++ void (*bond_cb_release)(struct net_device *slave); ++ void (*bond_cb_delete_by_slave)(struct net_device *slave); ++ void (*bond_cb_delete_by_mac)(uint8_t *mac_addr); ++}; ++ ++extern int bond_register_cb(struct bond_cb *cb); ++extern void bond_unregister_cb(void); ++/* QCA NSS ECM bonding support - End */ ++ + #endif /* _NET_BONDING_H */ diff --git a/6.1/target/linux/qualcommax/patches-6.1/0600-5-qca-nss-ecm-support-macvlan.patch b/6.1/target/linux/qualcommax/patches-6.1/0600-5-qca-nss-ecm-support-macvlan.patch new file mode 100644 index 000000000..5f18c6be7 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0600-5-qca-nss-ecm-support-macvlan.patch @@ -0,0 +1,96 @@ +--- a/include/linux/if_macvlan.h ++++ b/include/linux/if_macvlan.h +@@ -15,6 +15,13 @@ struct macvlan_port; + #define MACVLAN_MC_FILTER_BITS 8 + #define MACVLAN_MC_FILTER_SZ (1 << MACVLAN_MC_FILTER_BITS) + ++/* QCA NSS ECM Support - Start */ ++/* ++ * Callback for updating interface statistics for macvlan flows offloaded from host CPU. ++ */ ++typedef void (*macvlan_offload_stats_update_cb_t)(struct net_device *dev, struct rtnl_link_stats64 *stats, bool update_mcast_rx_stats); ++/* QCA NSS ECM Support - End */ ++ + struct macvlan_dev { + struct net_device *dev; + struct list_head list; +@@ -35,6 +42,7 @@ struct macvlan_dev { + #ifdef CONFIG_NET_POLL_CONTROLLER + struct netpoll *netpoll; + #endif ++ macvlan_offload_stats_update_cb_t offload_stats_update; /* QCA NSS ECM support */ + }; + + static inline void macvlan_count_rx(const struct macvlan_dev *vlan, +@@ -107,4 +115,26 @@ static inline int macvlan_release_l2fw_o + macvlan->accel_priv = NULL; + return dev_uc_add(macvlan->lowerdev, dev->dev_addr); + } ++ ++/* QCA NSS ECM Support - Start */ ++#if IS_ENABLED(CONFIG_MACVLAN) ++static inline void ++macvlan_offload_stats_update(struct net_device *dev, ++ struct rtnl_link_stats64 *stats, ++ bool update_mcast_rx_stats) ++{ ++ struct macvlan_dev *macvlan = netdev_priv(dev); ++ ++ macvlan->offload_stats_update(dev, stats, update_mcast_rx_stats); ++} ++ ++static inline enum ++macvlan_mode macvlan_get_mode(struct net_device *dev) ++{ ++ struct macvlan_dev *macvlan = netdev_priv(dev); ++ ++ return macvlan->mode; ++} ++#endif ++/* QCA NSS ECM Support - End */ + #endif /* _LINUX_IF_MACVLAN_H */ +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -933,6 +933,34 @@ static void macvlan_uninit(struct net_de + macvlan_port_destroy(port->dev); + } + ++/* QCA NSS ECM Support - Start */ ++/* Update macvlan statistics processed by offload engines */ ++static void macvlan_dev_update_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *offl_stats, ++ bool update_mcast_rx_stats) ++{ ++ struct vlan_pcpu_stats *stats; ++ struct macvlan_dev *macvlan; ++ ++ /* Is this a macvlan? */ ++ if (!netif_is_macvlan(dev)) ++ return; ++ ++ macvlan = netdev_priv(dev); ++ stats = this_cpu_ptr(macvlan->pcpu_stats); ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_add(&stats->rx_packets, offl_stats->rx_packets); ++ u64_stats_add(&stats->rx_bytes, offl_stats->rx_bytes); ++ u64_stats_add(&stats->tx_packets, offl_stats->tx_packets); ++ u64_stats_add(&stats->tx_bytes, offl_stats->tx_bytes); ++ /* Update multicast statistics */ ++ if (unlikely(update_mcast_rx_stats)) { ++ u64_stats_add(&stats->rx_multicast, offl_stats->rx_packets); ++ } ++ u64_stats_update_end(&stats->syncp); ++} ++/* QCA NSS ECM Support - End */ ++ + static void macvlan_dev_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) + { +@@ -1477,6 +1505,7 @@ int macvlan_common_newlink(struct net *s + vlan->dev = dev; + vlan->port = port; + vlan->set_features = MACVLAN_FEATURES; ++ vlan->offload_stats_update = macvlan_dev_update_stats; /* QCA NSS ECM Support */ + + vlan->mode = MACVLAN_MODE_VEPA; + if (data && data[IFLA_MACVLAN_MODE]) diff --git a/6.1/target/linux/qualcommax/patches-6.1/0600-6-qca-nss-ecm-support-netfilter-DSCPREMARK.patch b/6.1/target/linux/qualcommax/patches-6.1/0600-6-qca-nss-ecm-support-netfilter-DSCPREMARK.patch new file mode 100644 index 000000000..f9480406c --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0600-6-qca-nss-ecm-support-netfilter-DSCPREMARK.patch @@ -0,0 +1,154 @@ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -175,6 +175,13 @@ config NF_CONNTRACK_TIMEOUT + + If unsure, say `N'. + ++config NF_CONNTRACK_DSCPREMARK_EXT ++ bool 'Connection tracking extension for dscp remark target' ++ depends on NETFILTER_ADVANCED ++ help ++ This option enables support for connection tracking extension ++ for dscp remark. ++ + config NF_CONNTRACK_TIMESTAMP + bool 'Connection tracking timestamping' + depends on NETFILTER_ADVANCED +--- a/include/net/netfilter/nf_conntrack_extend.h ++++ b/include/net/netfilter/nf_conntrack_extend.h +@@ -31,6 +31,10 @@ enum nf_ct_ext_id { + #if IS_ENABLED(CONFIG_NET_ACT_CT) + NF_CT_EXT_ACT_CT, + #endif ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ NF_CT_EXT_DSCPREMARK, /* QCA NSS ECM support */ ++#endif ++ + NF_CT_EXT_NUM, + }; + +--- a/net/netfilter/nf_conntrack_extend.c ++++ b/net/netfilter/nf_conntrack_extend.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + + #define NF_CT_EXT_PREALLOC 128u /* conntrack events are on by default */ +@@ -54,6 +55,9 @@ static const u8 nf_ct_ext_type_len[NF_CT + #if IS_ENABLED(CONFIG_NET_ACT_CT) + [NF_CT_EXT_ACT_CT] = sizeof(struct nf_conn_act_ct_ext), + #endif ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ [NF_CT_EXT_DSCPREMARK] = sizeof(struct nf_ct_dscpremark_ext), ++#endif + }; + + static __always_inline unsigned int total_extension_size(void) +@@ -86,6 +90,9 @@ static __always_inline unsigned int tota + #if IS_ENABLED(CONFIG_NET_ACT_CT) + + sizeof(struct nf_conn_act_ct_ext) + #endif ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ + sizeof(struct nf_ct_dscpremark_ext) ++#endif + ; + } + +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -14,6 +14,7 @@ nf_conntrack-$(CONFIG_NF_CONNTRACK_LABEL + nf_conntrack-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o + nf_conntrack-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o + nf_conntrack-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o ++nf_conntrack-$(CONFIG_NF_CONNTRACK_DSCPREMARK_EXT) += nf_conntrack_dscpremark_ext.o + ifeq ($(CONFIG_NF_CONNTRACK),m) + nf_conntrack-$(CONFIG_DEBUG_INFO_BTF_MODULES) += nf_conntrack_bpf.o + else ifeq ($(CONFIG_NF_CONNTRACK),y) +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -45,6 +45,9 @@ + #include + #include + #include ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++#include ++#endif + #include + #include + #include +@@ -1781,6 +1784,9 @@ init_conntrack(struct net *net, struct n + nf_ct_acct_ext_add(ct, GFP_ATOMIC); + nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); + nf_ct_labels_ext_add(ct); ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ nf_ct_dscpremark_ext_add(ct, GFP_ATOMIC); ++#endif + + #ifdef CONFIG_NF_CONNTRACK_EVENTS + ecache = tmpl ? nf_ct_ecache_find(tmpl) : NULL; +--- a/net/netfilter/xt_DSCP.c ++++ b/net/netfilter/xt_DSCP.c +@@ -15,6 +15,9 @@ + + #include + #include ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++#include ++#endif + + MODULE_AUTHOR("Harald Welte "); + MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification"); +@@ -31,6 +34,10 @@ dscp_tg(struct sk_buff *skb, const struc + { + const struct xt_DSCP_info *dinfo = par->targinfo; + u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ struct nf_conn *ct; ++ enum ip_conntrack_info ctinfo; ++#endif + + if (dscp != dinfo->dscp) { + if (skb_ensure_writable(skb, sizeof(struct iphdr))) +@@ -39,6 +46,13 @@ dscp_tg(struct sk_buff *skb, const struc + ipv4_change_dsfield(ip_hdr(skb), XT_DSCP_ECN_MASK, + dinfo->dscp << XT_DSCP_SHIFT); + ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return XT_CONTINUE; ++ ++ nf_conntrack_dscpremark_ext_set_dscp_rule_valid(ct); ++#endif + } + return XT_CONTINUE; + } +@@ -48,13 +62,24 @@ dscp_tg6(struct sk_buff *skb, const stru + { + const struct xt_DSCP_info *dinfo = par->targinfo; + u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; +- ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ struct nf_conn *ct; ++ enum ip_conntrack_info ctinfo; ++#endif + if (dscp != dinfo->dscp) { + if (skb_ensure_writable(skb, sizeof(struct ipv6hdr))) + return NF_DROP; + + ipv6_change_dsfield(ipv6_hdr(skb), XT_DSCP_ECN_MASK, + dinfo->dscp << XT_DSCP_SHIFT); ++ ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return XT_CONTINUE; ++ ++ nf_conntrack_dscpremark_ext_set_dscp_rule_valid(ct); ++#endif + } + return XT_CONTINUE; + } diff --git a/6.1/target/linux/qualcommax/patches-6.1/0600-7-qca-nss-ecm-fix-IPv6-user-route-change-event-calls.patch b/6.1/target/linux/qualcommax/patches-6.1/0600-7-qca-nss-ecm-fix-IPv6-user-route-change-event-calls.patch new file mode 100644 index 000000000..4fd75771c --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0600-7-qca-nss-ecm-fix-IPv6-user-route-change-event-calls.patch @@ -0,0 +1,89 @@ +From ce18a6fdff6a39a01111d74f513d2ef66142047c Mon Sep 17 00:00:00 2001 +From: Murat Sezgin +Date: Wed, 5 Aug 2020 13:21:27 -0700 +Subject: [PATCH 246/281] net:ipv6: Fix IPv6 user route change event calls + +These events should be called only when the route table is +changed by the userspace. So, we should call them in the +ioctl and the netlink message handler function. + +Change-Id: If7ec615014cfc79d5fa72878e49eaf99c2560c32 +Signed-off-by: Murat Sezgin +--- + net/ipv6/route.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index df82117..4fb8247 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -3868,10 +3868,6 @@ int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags, + return PTR_ERR(rt); + + err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack); +- if (!err) +- atomic_notifier_call_chain(&ip6route_chain, +- RTM_NEWROUTE, rt); +- + fib6_info_release(rt); + + return err; +@@ -3893,9 +3889,6 @@ static int __ip6_del_rt(struct fib6_info *rt, struct nl_info *info) + err = fib6_del(rt, info); + spin_unlock_bh(&table->tb6_lock); + +- if (!err) +- atomic_notifier_call_chain(&ip6route_chain, +- RTM_DELROUTE, rt); + out: + fib6_info_release(rt); + return err; +@@ -4501,6 +4494,10 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, struct in6_rtmsg *rtmsg) + break; + } + rtnl_unlock(); ++ if (!err) ++ atomic_notifier_call_chain(&ip6route_chain, ++ (cmd == SIOCADDRT) ? RTM_NEWROUTE : RTM_DELROUTE, &cfg); ++ + return err; + } + +@@ -5528,11 +5525,17 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, + } + + if (cfg.fc_mp) +- return ip6_route_multipath_del(&cfg, extack); ++ err = ip6_route_multipath_del(&cfg, extack); + else { + cfg.fc_delete_all_nh = 1; +- return ip6_route_del(&cfg, extack); ++ err = ip6_route_del(&cfg, extack); + } ++ ++ if (!err) ++ atomic_notifier_call_chain(&ip6route_chain, ++ RTM_DELROUTE, &cfg); ++ ++ return err; + } + + static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, +@@ -5549,9 +5552,15 @@ static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, + cfg.fc_metric = IP6_RT_PRIO_USER; + + if (cfg.fc_mp) +- return ip6_route_multipath_add(&cfg, extack); ++ err = ip6_route_multipath_add(&cfg, extack); + else +- return ip6_route_add(&cfg, GFP_KERNEL, extack); ++ err = ip6_route_add(&cfg, GFP_KERNEL, extack); ++ ++ if (!err) ++ atomic_notifier_call_chain(&ip6route_chain, ++ RTM_NEWROUTE, &cfg); ++ ++ return err; + } + + /* add the overhead of this fib6_nh to nexthop_len */ diff --git a/6.1/target/linux/qualcommax/patches-6.1/0601-1-qca-add-nss-bridge-mgr-support.patch b/6.1/target/linux/qualcommax/patches-6.1/0601-1-qca-add-nss-bridge-mgr-support.patch new file mode 100644 index 000000000..86e2f4fa5 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0601-1-qca-add-nss-bridge-mgr-support.patch @@ -0,0 +1,92 @@ +From 3c17a0e1112be70071e98d5208da5b55dcec20a6 Mon Sep 17 00:00:00 2001 +From: Simon Casey +Date: Wed, 2 Feb 2022 19:37:29 +0100 +Subject: [PATCH] Update 607-qca-add-add-nss-bridge-mgr-support.patch for kernel 5.15 + +--- + include/linux/if_bridge.h | 4 ++++ + net/bridge/br_fdb.c | 25 +++++++++++++++++++++---- + 2 files changed, 25 insertions(+), 4 deletions(-) + +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -252,4 +252,8 @@ typedef struct net_bridge_port *br_get_d + extern br_get_dst_hook_t __rcu *br_get_dst_hook; + /* QCA NSS ECM support - End */ + ++/* QCA NSS bridge-mgr support - Start */ ++extern struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br); ++/* QCA NSS bridge-mgr support - End */ ++ + #endif +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -569,7 +569,7 @@ void br_fdb_cleanup(struct work_struct * + unsigned long delay = hold_time(br); + unsigned long work_delay = delay; + unsigned long now = jiffies; +- u8 mac_addr[6]; /* QCA NSS ECM support */ ++ struct br_fdb_event fdb_event; /* QCA NSS bridge-mgr support */ + + /* this part is tricky, in order to avoid blocking learning and + * consequently forwarding, we rely on rcu to delete objects with +@@ -597,12 +597,13 @@ void br_fdb_cleanup(struct work_struct * + } else { + spin_lock_bh(&br->hash_lock); + if (!hlist_unhashed(&f->fdb_node)) { +- ether_addr_copy(mac_addr, f->key.addr.addr); ++ memset(&fdb_event, 0, sizeof(fdb_event)); ++ ether_addr_copy(fdb_event.addr, f->key.addr.addr); + fdb_delete(br, f, true); + /* QCA NSS ECM support - Start */ + atomic_notifier_call_chain( + &br_fdb_update_notifier_list, 0, +- (void *)mac_addr); ++ (void *)&fdb_event); + /* QCA NSS ECM support - End */ + } + spin_unlock_bh(&br->hash_lock); +@@ -900,10 +901,21 @@ static bool __fdb_mark_active(struct net + test_and_clear_bit(BR_FDB_NOTIFY_INACTIVE, &fdb->flags)); + } + ++/* QCA NSS bridge-mgr support - Start */ ++/* Get the bridge device */ ++struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br) ++{ ++ dev_hold(br->dev); ++ return br->dev; ++} ++EXPORT_SYMBOL_GPL(br_fdb_bridge_dev_get_and_hold); ++/* QCA NSS bridge-mgr support - End */ ++ + void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, + const unsigned char *addr, u16 vid, unsigned long flags) + { + struct net_bridge_fdb_entry *fdb; ++ struct br_fdb_event fdb_event; /* QCA NSS bridge-mgr support */ + + /* some users want to always flood. */ + if (hold_time(br) == 0) +@@ -929,6 +941,12 @@ void br_fdb_update(struct net_bridge *br + if (unlikely(source != READ_ONCE(fdb->dst) && + !test_bit(BR_FDB_STICKY, &fdb->flags))) { + br_switchdev_fdb_notify(br, fdb, RTM_DELNEIGH); ++ /* QCA NSS bridge-mgr support - Start */ ++ ether_addr_copy(fdb_event.addr, addr); ++ fdb_event.br = br; ++ fdb_event.orig_dev = fdb->dst->dev; ++ fdb_event.dev = source->dev; ++ /* QCA NSS bridge-mgr support - End */ + WRITE_ONCE(fdb->dst, source); + fdb_modified = true; + /* Take over HW learned entry */ +@@ -940,7 +958,7 @@ void br_fdb_update(struct net_bridge *br + /* QCA NSS ECM support - Start */ + atomic_notifier_call_chain( + &br_fdb_update_notifier_list, +- 0, (void *)addr); ++ 0, (void *)&fdb_event); + /* QCA NSS ECM support - End */ + } + diff --git a/6.1/target/linux/qualcommax/patches-6.1/0602-1-qca-nss-drv-add-qdisc-support.patch b/6.1/target/linux/qualcommax/patches-6.1/0602-1-qca-nss-drv-add-qdisc-support.patch new file mode 100644 index 000000000..bbffeb1f0 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0602-1-qca-nss-drv-add-qdisc-support.patch @@ -0,0 +1,44 @@ +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -773,6 +773,7 @@ typedef unsigned char *sk_buff_data_t; + * @offload_fwd_mark: Packet was L2-forwarded in hardware + * @offload_l3_fwd_mark: Packet was L3-forwarded in hardware + * @tc_skip_classify: do not classify packet. set by IFB device ++ * @tc_skip_classify_offload: do not classify packet set by offload IFB device + * @tc_at_ingress: used within tc_classify to distinguish in/egress + * @redirected: packet was redirected by packet classifier + * @from_ingress: packet was redirected from the ingress path +@@ -968,6 +969,8 @@ struct sk_buff { + #ifdef CONFIG_NET_CLS_ACT + __u8 tc_skip_classify:1; + __u8 tc_at_ingress:1; /* See TC_AT_INGRESS_MASK */ ++ __u8 tc_skip_classify_offload:1; ++ __u16 tc_verd_qca_nss; /* QCA NSS Qdisc Support */ + #endif + #ifdef CONFIG_IPV6_NDISC_NODETYPE + __u8 ndisc_nodetype:2; +--- a/include/uapi/linux/pkt_cls.h ++++ b/include/uapi/linux/pkt_cls.h +@@ -139,6 +139,7 @@ enum tca_id { + TCA_ID_MPLS, + TCA_ID_CT, + TCA_ID_GATE, ++ TCA_ID_MIRRED_NSS, /* QCA NSS Qdisc IGS Support */ + /* other actions go here */ + __TCA_ID_MAX = 255 + }; +@@ -801,4 +802,14 @@ enum { + TCF_EM_OPND_LT + }; + ++/* QCA NSS Qdisc Support - Start */ ++#define _TC_MAKE32(x) ((x)) ++#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n)) ++ ++#define TC_NCLS _TC_MAKEMASK1(8) ++#define TC_NCLS_NSS _TC_MAKEMASK1(12) ++#define SET_TC_NCLS_NSS(v) ( TC_NCLS_NSS | ((v) & ~TC_NCLS_NSS)) ++#define CLR_TC_NCLS_NSS(v) ( (v) & ~TC_NCLS_NSS) ++/* QCA NSS Qdisc Support - End */ ++ + #endif diff --git a/6.1/target/linux/qualcommax/patches-6.1/0603-1-qca-nss-clients-add-qdisc-support.patch b/6.1/target/linux/qualcommax/patches-6.1/0603-1-qca-nss-clients-add-qdisc-support.patch new file mode 100644 index 000000000..671516cfc --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0603-1-qca-nss-clients-add-qdisc-support.patch @@ -0,0 +1,441 @@ +--- a/include/linux/timer.h ++++ b/include/linux/timer.h +@@ -17,6 +17,7 @@ struct timer_list { + unsigned long expires; + void (*function)(struct timer_list *); + u32 flags; ++ unsigned long cust_data; + + #ifdef CONFIG_LOCKDEP + struct lockdep_map lockdep_map; +--- a/drivers/net/ifb.c ++++ b/drivers/net/ifb.c +@@ -151,6 +151,31 @@ resched: + + } + ++void ifb_update_offload_stats(struct net_device *dev, struct pcpu_sw_netstats *offload_stats) ++{ ++ struct ifb_dev_private *dp; ++ struct ifb_q_private *txp; ++ ++ if (!dev || !offload_stats) { ++ return; ++ } ++ ++ if (!(dev->priv_flags_ext & IFF_EXT_IFB)) { ++ return; ++ } ++ ++ dp = netdev_priv(dev); ++ txp = dp->tx_private; ++ ++ u64_stats_update_begin(&txp->rx_stats.sync); ++ txp->rx_stats.packets += u64_stats_read(&offload_stats->rx_packets); ++ txp->rx_stats.bytes += u64_stats_read(&offload_stats->rx_bytes); ++ txp->tx_stats.packets += u64_stats_read(&offload_stats->tx_packets); ++ txp->tx_stats.bytes += u64_stats_read(&offload_stats->tx_bytes); ++ u64_stats_update_end(&txp->rx_stats.sync); ++} ++EXPORT_SYMBOL(ifb_update_offload_stats); ++ + static void ifb_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) + { +@@ -326,6 +351,7 @@ static void ifb_setup(struct net_device + dev->flags |= IFF_NOARP; + dev->flags &= ~IFF_MULTICAST; + dev->priv_flags &= ~IFF_TX_SKB_SHARING; ++ dev->priv_flags_ext |= IFF_EXT_IFB; /* Mark the device as an IFB device. */ + netif_keep_dst(dev); + eth_hw_addr_random(dev); + dev->needs_free_netdev = true; +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -4588,6 +4588,15 @@ void dev_uc_flush(struct net_device *dev + void dev_uc_init(struct net_device *dev); + + /** ++ * ifb_update_offload_stats - Update the IFB interface stats ++ * @dev: IFB device to update the stats ++ * @offload_stats: per CPU stats structure ++ * ++ * Allows update of IFB stats when flows are offloaded to an accelerator. ++ **/ ++void ifb_update_offload_stats(struct net_device *dev, struct pcpu_sw_netstats *offload_stats); ++ ++/** + * __dev_uc_sync - Synchonize device's unicast list + * @dev: device to sync + * @sync: function to call if address should be added +@@ -5133,6 +5142,11 @@ static inline bool netif_is_failover_sla + return dev->priv_flags & IFF_FAILOVER_SLAVE; + } + ++static inline bool netif_is_ifb_dev(const struct net_device *dev) ++{ ++ return dev->priv_flags_ext & IFF_EXT_IFB; ++} ++ + /* This device needs to keep skb dst for qdisc enqueue or ndo_start_xmit() */ + static inline void netif_keep_dst(struct net_device *dev) + { +--- a/include/uapi/linux/pkt_sched.h ++++ b/include/uapi/linux/pkt_sched.h +@@ -1278,4 +1278,248 @@ enum { + + #define TCA_ETS_MAX (__TCA_ETS_MAX - 1) + ++/* QCA NSS Clients Support - Start */ ++enum { ++ TCA_NSS_ACCEL_MODE_NSS_FW, ++ TCA_NSS_ACCEL_MODE_PPE, ++ TCA_NSS_ACCEL_MODE_MAX ++}; ++ ++/* NSSFIFO section */ ++ ++enum { ++ TCA_NSSFIFO_UNSPEC, ++ TCA_NSSFIFO_PARMS, ++ __TCA_NSSFIFO_MAX ++}; ++ ++#define TCA_NSSFIFO_MAX (__TCA_NSSFIFO_MAX - 1) ++ ++struct tc_nssfifo_qopt { ++ __u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */ ++ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSWRED section */ ++ ++enum { ++ TCA_NSSWRED_UNSPEC, ++ TCA_NSSWRED_PARMS, ++ __TCA_NSSWRED_MAX ++}; ++ ++#define TCA_NSSWRED_MAX (__TCA_NSSWRED_MAX - 1) ++#define NSSWRED_CLASS_MAX 6 ++struct tc_red_alg_parameter { ++ __u32 min; /* qlen_avg < min: pkts are all enqueued */ ++ __u32 max; /* qlen_avg > max: pkts are all dropped */ ++ __u32 probability;/* Drop probability at qlen_avg = max */ ++ __u32 exp_weight_factor;/* exp_weight_factor for calculate qlen_avg */ ++}; ++ ++struct tc_nsswred_traffic_class { ++ __u32 limit; /* Queue length */ ++ __u32 weight_mode_value; /* Weight mode value */ ++ struct tc_red_alg_parameter rap;/* Parameters for RED alg */ ++}; ++ ++/* ++ * Weight modes for WRED ++ */ ++enum tc_nsswred_weight_modes { ++ TC_NSSWRED_WEIGHT_MODE_DSCP = 0,/* Weight mode is DSCP */ ++ TC_NSSWRED_WEIGHT_MODES, /* Must be last */ ++}; ++ ++struct tc_nsswred_qopt { ++ __u32 limit; /* Queue length */ ++ enum tc_nsswred_weight_modes weight_mode; ++ /* Weight mode */ ++ __u32 traffic_classes; /* How many traffic classes: DPs */ ++ __u32 def_traffic_class; /* Default traffic if no match: def_DP */ ++ __u32 traffic_id; /* The traffic id to be configured: DP */ ++ __u32 weight_mode_value; /* Weight mode value */ ++ struct tc_red_alg_parameter rap;/* RED algorithm parameters */ ++ struct tc_nsswred_traffic_class tntc[NSSWRED_CLASS_MAX]; ++ /* Traffic settings for dumpping */ ++ __u8 ecn; /* Setting ECN bit or dropping */ ++ __u8 set_default; /* Sets qdisc to be the default for enqueue */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSCODEL section */ ++ ++enum { ++ TCA_NSSCODEL_UNSPEC, ++ TCA_NSSCODEL_PARMS, ++ __TCA_NSSCODEL_MAX ++}; ++ ++#define TCA_NSSCODEL_MAX (__TCA_NSSCODEL_MAX - 1) ++ ++struct tc_nsscodel_qopt { ++ __u32 target; /* Acceptable queueing delay */ ++ __u32 limit; /* Max number of packets that can be held in the queue */ ++ __u32 interval; /* Monitoring interval */ ++ __u32 flows; /* Number of flow buckets */ ++ __u32 quantum; /* Weight (in bytes) used for DRR of flow buckets */ ++ __u8 ecn; /* 0 - disable ECN, 1 - enable ECN */ ++ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++struct tc_nsscodel_xstats { ++ __u32 peak_queue_delay; /* Peak delay experienced by a dequeued packet */ ++ __u32 peak_drop_delay; /* Peak delay experienced by a dropped packet */ ++}; ++ ++/* NSSFQ_CODEL section */ ++ ++struct tc_nssfq_codel_xstats { ++ __u32 new_flow_count; /* Total number of new flows seen */ ++ __u32 new_flows_len; /* Current number of new flows */ ++ __u32 old_flows_len; /* Current number of old flows */ ++ __u32 ecn_mark; /* Number of packets marked with ECN */ ++ __u32 drop_overlimit; /* Number of packets dropped due to overlimit */ ++ __u32 maxpacket; /* The largest packet seen so far in the queue */ ++}; ++ ++/* NSSTBL section */ ++ ++enum { ++ TCA_NSSTBL_UNSPEC, ++ TCA_NSSTBL_PARMS, ++ __TCA_NSSTBL_MAX ++}; ++ ++#define TCA_NSSTBL_MAX (__TCA_NSSTBL_MAX - 1) ++ ++struct tc_nsstbl_qopt { ++ __u32 burst; /* Maximum burst size */ ++ __u32 rate; /* Limiting rate of TBF */ ++ __u32 peakrate; /* Maximum rate at which TBF is allowed to send */ ++ __u32 mtu; /* Max size of packet, or minumim burst size */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSPRIO section */ ++ ++#define TCA_NSSPRIO_MAX_BANDS 256 ++ ++enum { ++ TCA_NSSPRIO_UNSPEC, ++ TCA_NSSPRIO_PARMS, ++ __TCA_NSSPRIO_MAX ++}; ++ ++#define TCA_NSSPRIO_MAX (__TCA_NSSPRIO_MAX - 1) ++ ++struct tc_nssprio_qopt { ++ __u32 bands; /* Number of bands */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSBF section */ ++ ++enum { ++ TCA_NSSBF_UNSPEC, ++ TCA_NSSBF_CLASS_PARMS, ++ TCA_NSSBF_QDISC_PARMS, ++ __TCA_NSSBF_MAX ++}; ++ ++#define TCA_NSSBF_MAX (__TCA_NSSBF_MAX - 1) ++ ++struct tc_nssbf_class_qopt { ++ __u32 burst; /* Maximum burst size */ ++ __u32 rate; /* Allowed bandwidth for this class */ ++ __u32 mtu; /* MTU of the associated interface */ ++ __u32 quantum; /* Quantum allocation for DRR */ ++}; ++ ++struct tc_nssbf_qopt { ++ __u16 defcls; /* Default class value */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSWRR section */ ++ ++enum { ++ TCA_NSSWRR_UNSPEC, ++ TCA_NSSWRR_CLASS_PARMS, ++ TCA_NSSWRR_QDISC_PARMS, ++ __TCA_NSSWRR_MAX ++}; ++ ++#define TCA_NSSWRR_MAX (__TCA_NSSWRR_MAX - 1) ++ ++struct tc_nsswrr_class_qopt { ++ __u32 quantum; /* Weight associated to this class */ ++}; ++ ++struct tc_nsswrr_qopt { ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSWFQ section */ ++ ++enum { ++ TCA_NSSWFQ_UNSPEC, ++ TCA_NSSWFQ_CLASS_PARMS, ++ TCA_NSSWFQ_QDISC_PARMS, ++ __TCA_NSSWFQ_MAX ++}; ++ ++#define TCA_NSSWFQ_MAX (__TCA_NSSWFQ_MAX - 1) ++ ++struct tc_nsswfq_class_qopt { ++ __u32 quantum; /* Weight associated to this class */ ++}; ++ ++struct tc_nsswfq_qopt { ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSHTB section */ ++ ++enum { ++ TCA_NSSHTB_UNSPEC, ++ TCA_NSSHTB_CLASS_PARMS, ++ TCA_NSSHTB_QDISC_PARMS, ++ __TCA_NSSHTB_MAX ++}; ++ ++#define TCA_NSSHTB_MAX (__TCA_NSSHTB_MAX - 1) ++ ++struct tc_nsshtb_class_qopt { ++ __u32 burst; /* Allowed burst size */ ++ __u32 rate; /* Allowed bandwidth for this class */ ++ __u32 cburst; /* Maximum burst size */ ++ __u32 crate; /* Maximum bandwidth for this class */ ++ __u32 quantum; /* Quantum allocation for DRR */ ++ __u32 priority; /* Priority value associated with this class */ ++ __u32 overhead; /* Overhead in bytes per packet */ ++}; ++ ++struct tc_nsshtb_qopt { ++ __u32 r2q; /* Rate to quantum ratio */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSBLACKHOLE section */ ++ ++enum { ++ TCA_NSSBLACKHOLE_UNSPEC, ++ TCA_NSSBLACKHOLE_PARMS, ++ __TCA_NSSBLACKHOLE_MAX ++}; ++ ++#define TCA_NSSBLACKHOLE_MAX (__TCA_NSSBLACKHOLE_MAX - 1) ++ ++struct tc_nssblackhole_qopt { ++ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++/* QCA NSS Clients Support - End */ + #endif +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -313,6 +313,7 @@ struct Qdisc *qdisc_lookup(struct net_de + out: + return q; + } ++EXPORT_SYMBOL(qdisc_lookup); + + struct Qdisc *qdisc_lookup_rcu(struct net_device *dev, u32 handle) + { +@@ -2386,4 +2387,26 @@ static int __init pktsched_init(void) + return 0; + } + ++/* QCA NSS Qdisc Support - Start */ ++bool tcf_destroy(struct tcf_proto *tp, bool force) ++{ ++ tp->ops->destroy(tp, force, NULL); ++ module_put(tp->ops->owner); ++ kfree_rcu(tp, rcu); ++ ++ return true; ++} ++ ++void tcf_destroy_chain(struct tcf_proto __rcu **fl) ++{ ++ struct tcf_proto *tp; ++ ++ while ((tp = rtnl_dereference(*fl)) != NULL) { ++ RCU_INIT_POINTER(*fl, tp->next); ++ tcf_destroy(tp, true); ++ } ++} ++EXPORT_SYMBOL(tcf_destroy_chain); ++/* QCA NSS Qdisc Support - End */ ++ + subsys_initcall(pktsched_init); +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -1069,6 +1069,7 @@ static void __qdisc_destroy(struct Qdisc + + call_rcu(&qdisc->rcu, qdisc_free_cb); + } ++EXPORT_SYMBOL(qdisc_destroy); + + void qdisc_destroy(struct Qdisc *qdisc) + { +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -94,6 +94,7 @@ struct Qdisc { + #define TCQ_F_INVISIBLE 0x80 /* invisible by default in dump */ + #define TCQ_F_NOLOCK 0x100 /* qdisc does not require locking */ + #define TCQ_F_OFFLOADED 0x200 /* qdisc is offloaded to HW */ ++#define TCQ_F_NSS 0x1000 /* NSS qdisc flag. */ + u32 limit; + const struct Qdisc_ops *ops; + struct qdisc_size_table __rcu *stab; +@@ -719,6 +720,40 @@ static inline bool skb_skip_tc_classify( + return false; + } + ++/* ++ * Set skb classify bit field. ++ */ ++static inline void skb_set_tc_classify_offload(struct sk_buff *skb) ++{ ++#ifdef CONFIG_NET_CLS_ACT ++ skb->tc_skip_classify_offload = 1; ++#endif ++} ++ ++/* ++ * Clear skb classify bit field. ++ */ ++static inline void skb_clear_tc_classify_offload(struct sk_buff *skb) ++{ ++#ifdef CONFIG_NET_CLS_ACT ++ skb->tc_skip_classify_offload = 0; ++#endif ++} ++ ++/* ++ * Skip skb processing if sent from ifb dev. ++ */ ++static inline bool skb_skip_tc_classify_offload(struct sk_buff *skb) ++{ ++#ifdef CONFIG_NET_CLS_ACT ++ if (skb->tc_skip_classify_offload) { ++ skb_clear_tc_classify_offload(skb); ++ return true; ++ } ++#endif ++ return false; ++} ++ + /* Reset all TX qdiscs greater than index of a device. */ + static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i) + { +@@ -1305,4 +1340,9 @@ static inline void qdisc_synchronize(con + msleep(1); + } + ++/* QCA NSS Qdisc Support - Start */ ++void qdisc_destroy(struct Qdisc *qdisc); ++void tcf_destroy_chain(struct tcf_proto __rcu **fl); ++/* QCA NSS Qdisc Support - End */ ++ + #endif diff --git a/6.1/target/linux/qualcommax/patches-6.1/0603-2-qca-nss-clients-add-l2tp-support.patch b/6.1/target/linux/qualcommax/patches-6.1/0603-2-qca-nss-clients-add-l2tp-support.patch new file mode 100644 index 000000000..7fa9184df --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0603-2-qca-nss-clients-add-l2tp-support.patch @@ -0,0 +1,46 @@ +--- a/net/l2tp/l2tp_core.c ++++ b/net/l2tp/l2tp_core.c +@@ -398,6 +398,31 @@ err_tlock: + } + EXPORT_SYMBOL_GPL(l2tp_session_register); + ++void l2tp_stats_update(struct l2tp_tunnel *tunnel, ++ struct l2tp_session *session, ++ struct l2tp_stats *stats) ++{ ++ atomic_long_add(atomic_long_read(&stats->rx_packets), ++ &tunnel->stats.rx_packets); ++ atomic_long_add(atomic_long_read(&stats->rx_bytes), ++ &tunnel->stats.rx_bytes); ++ atomic_long_add(atomic_long_read(&stats->tx_packets), ++ &tunnel->stats.tx_packets); ++ atomic_long_add(atomic_long_read(&stats->tx_bytes), ++ &tunnel->stats.tx_bytes); ++ ++ atomic_long_add(atomic_long_read(&stats->rx_packets), ++ &session->stats.rx_packets); ++ atomic_long_add(atomic_long_read(&stats->rx_bytes), ++ &session->stats.rx_bytes); ++ atomic_long_add(atomic_long_read(&stats->tx_packets), ++ &session->stats.tx_packets); ++ atomic_long_add(atomic_long_read(&stats->tx_bytes), ++ &session->stats.tx_bytes); ++} ++EXPORT_SYMBOL_GPL(l2tp_stats_update); ++ ++ + /***************************************************************************** + * Receive data handling + *****************************************************************************/ +--- a/net/l2tp/l2tp_core.h ++++ b/net/l2tp/l2tp_core.h +@@ -232,6 +232,9 @@ struct l2tp_session *l2tp_session_get_nt + struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net, + const char *ifname); + ++void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session, ++ struct l2tp_stats *stats); ++ + /* Tunnel and session lifetime management. + * Creation of a new instance is a two-step process: create, then register. + * Destruction is triggered using the *_delete functions, and completes asynchronously. diff --git a/6.1/target/linux/qualcommax/patches-6.1/0603-3-qca-nss-clients-add-PPTP-support.patch b/6.1/target/linux/qualcommax/patches-6.1/0603-3-qca-nss-clients-add-PPTP-support.patch new file mode 100644 index 000000000..5fb9917bc --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0603-3-qca-nss-clients-add-PPTP-support.patch @@ -0,0 +1,478 @@ +--- a/include/linux/if_pppox.h ++++ b/include/linux/if_pppox.h +@@ -36,6 +36,7 @@ struct pptp_opt { + u32 ack_sent, ack_recv; + u32 seq_sent, seq_recv; + int ppp_flags; ++ bool pptp_offload_mode; + }; + #include + +@@ -100,8 +101,40 @@ struct pppoe_channel_ops { + int (*get_addressing)(struct ppp_channel *, struct pppoe_opt *); + }; + ++/* PPTP client callback */ ++typedef int (*pptp_gre_seq_offload_callback_t)(struct sk_buff *skb, ++ struct net_device *pptp_dev); ++ + /* Return PPPoE channel specific addressing information */ + extern int pppoe_channel_addressing_get(struct ppp_channel *chan, + struct pppoe_opt *addressing); + ++/* Lookup PPTP session info and return PPTP session using sip, dip and local call id */ ++extern int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id, ++ __be32 daddr, __be32 saddr); ++ ++/* Lookup PPTP session info and return PPTP session using dip and peer call id */ ++extern int pptp_session_find(struct pptp_opt *opt, __be16 peer_call_id, ++ __be32 peer_ip_addr); ++ ++/* Return PPTP session information given the channel */ ++extern void pptp_channel_addressing_get(struct pptp_opt *opt, ++ struct ppp_channel *chan); ++ ++/* Enable the PPTP session offload flag */ ++extern int pptp_session_enable_offload_mode(__be16 peer_call_id, ++ __be32 peer_ip_addr); ++ ++/* Disable the PPTP session offload flag */ ++extern int pptp_session_disable_offload_mode(__be16 peer_call_id, ++ __be32 peer_ip_addr); ++ ++/* Register the PPTP GRE packets sequence number offload callback */ ++extern int ++pptp_register_gre_seq_offload_callback(pptp_gre_seq_offload_callback_t ++ pptp_client_cb); ++ ++/* Unregister the PPTP GRE packets sequence number offload callback */ ++extern void pptp_unregister_gre_seq_offload_callback(void); ++ + #endif /* !(__LINUX_IF_PPPOX_H) */ +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -2973,6 +2973,20 @@ char *ppp_dev_name(struct ppp_channel *c + return name; + } + ++/* Return the PPP net device index */ ++int ppp_dev_index(struct ppp_channel *chan) ++{ ++ struct channel *pch = chan->ppp; ++ int ifindex = 0; ++ ++ if (pch) { ++ read_lock_bh(&pch->upl); ++ if (pch->ppp && pch->ppp->dev) ++ ifindex = pch->ppp->dev->ifindex; ++ read_unlock_bh(&pch->upl); ++ } ++ return ifindex; ++} + + /* + * Disconnect a channel from the generic layer. +@@ -3681,6 +3695,28 @@ void ppp_update_stats(struct net_device + ppp_recv_unlock(ppp); + } + ++/* Returns true if Compression is enabled on PPP device ++ */ ++bool ppp_is_cp_enabled(struct net_device *dev) ++{ ++ struct ppp *ppp; ++ bool flag = false; ++ ++ if (!dev) ++ return false; ++ ++ if (dev->type != ARPHRD_PPP) ++ return false; ++ ++ ppp = netdev_priv(dev); ++ ppp_lock(ppp); ++ flag = !!(ppp->xstate & SC_COMP_RUN) || !!(ppp->rstate & SC_DECOMP_RUN); ++ ppp_unlock(ppp); ++ ++ return flag; ++} ++EXPORT_SYMBOL(ppp_is_cp_enabled); ++ + /* Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 if + * the device is not PPP. + */ +@@ -3872,6 +3908,7 @@ EXPORT_SYMBOL(ppp_unregister_channel); + EXPORT_SYMBOL(ppp_channel_index); + EXPORT_SYMBOL(ppp_unit_number); + EXPORT_SYMBOL(ppp_dev_name); ++EXPORT_SYMBOL(ppp_dev_index); + EXPORT_SYMBOL(ppp_input); + EXPORT_SYMBOL(ppp_input_error); + EXPORT_SYMBOL(ppp_output_wakeup); +--- a/include/linux/ppp_channel.h ++++ b/include/linux/ppp_channel.h +@@ -84,6 +84,9 @@ extern void ppp_unregister_channel(struc + /* Get the channel number for a channel */ + extern int ppp_channel_index(struct ppp_channel *); + ++/* Get the device index associated with a channel, or 0, if none */ ++extern int ppp_dev_index(struct ppp_channel *); ++ + /* Get the unit number associated with a channel, or -1 if none */ + extern int ppp_unit_number(struct ppp_channel *); + +@@ -116,6 +119,7 @@ extern int ppp_hold_channels(struct net_ + /* Test if ppp xmit lock is locked */ + extern bool ppp_is_xmit_locked(struct net_device *dev); + ++bool ppp_is_cp_enabled(struct net_device *dev); + /* Test if the ppp device is a multi-link ppp device */ + extern int ppp_is_multilink(struct net_device *dev); + +--- a/drivers/net/ppp/pptp.c ++++ b/drivers/net/ppp/pptp.c +@@ -50,6 +50,8 @@ static struct proto pptp_sk_proto __read + static const struct ppp_channel_ops pptp_chan_ops; + static const struct proto_ops pptp_ops; + ++static pptp_gre_seq_offload_callback_t __rcu pptp_gre_offload_xmit_cb; ++ + static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr) + { + struct pppox_sock *sock; +@@ -91,6 +93,79 @@ static int lookup_chan_dst(u16 call_id, + return i < MAX_CALLID; + } + ++/* Search a pptp session based on local call id, local and remote ip address */ ++static int lookup_session_src(struct pptp_opt *opt, u16 call_id, __be32 daddr, __be32 saddr) ++{ ++ struct pppox_sock *sock; ++ int i = 1; ++ ++ rcu_read_lock(); ++ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) { ++ sock = rcu_dereference(callid_sock[i]); ++ if (!sock) ++ continue; ++ ++ if (sock->proto.pptp.src_addr.call_id == call_id && ++ sock->proto.pptp.dst_addr.sin_addr.s_addr == daddr && ++ sock->proto.pptp.src_addr.sin_addr.s_addr == saddr) { ++ sock_hold(sk_pppox(sock)); ++ memcpy(opt, &sock->proto.pptp, sizeof(struct pptp_opt)); ++ sock_put(sk_pppox(sock)); ++ rcu_read_unlock(); ++ return 0; ++ } ++ } ++ rcu_read_unlock(); ++ return -EINVAL; ++} ++ ++/* Search a pptp session based on peer call id and peer ip address */ ++static int lookup_session_dst(struct pptp_opt *opt, u16 call_id, __be32 d_addr) ++{ ++ struct pppox_sock *sock; ++ int i = 1; ++ ++ rcu_read_lock(); ++ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) { ++ sock = rcu_dereference(callid_sock[i]); ++ if (!sock) ++ continue; ++ ++ if (sock->proto.pptp.dst_addr.call_id == call_id && ++ sock->proto.pptp.dst_addr.sin_addr.s_addr == d_addr) { ++ sock_hold(sk_pppox(sock)); ++ memcpy(opt, &sock->proto.pptp, sizeof(struct pptp_opt)); ++ sock_put(sk_pppox(sock)); ++ rcu_read_unlock(); ++ return 0; ++ } ++ } ++ rcu_read_unlock(); ++ return -EINVAL; ++} ++ ++/* If offload mode set then this function sends all packets to ++ * offload module instead of network stack ++ */ ++static int pptp_client_skb_xmit(struct sk_buff *skb, ++ struct net_device *pptp_dev) ++{ ++ pptp_gre_seq_offload_callback_t pptp_gre_offload_cb_f; ++ int ret; ++ ++ rcu_read_lock(); ++ pptp_gre_offload_cb_f = rcu_dereference(pptp_gre_offload_xmit_cb); ++ ++ if (!pptp_gre_offload_cb_f) { ++ rcu_read_unlock(); ++ return -1; ++ } ++ ++ ret = pptp_gre_offload_cb_f(skb, pptp_dev); ++ rcu_read_unlock(); ++ return ret; ++} ++ + static int add_chan(struct pppox_sock *sock, + struct pptp_addr *sa) + { +@@ -136,7 +211,7 @@ static struct rtable *pptp_route_output( + struct net *net; + + net = sock_net(sk); +- flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, 0, ++ flowi4_init_output(fl4, 0, sk->sk_mark, 0, + RT_SCOPE_UNIVERSE, IPPROTO_GRE, 0, + po->proto.pptp.dst_addr.sin_addr.s_addr, + po->proto.pptp.src_addr.sin_addr.s_addr, +@@ -163,8 +238,11 @@ static int pptp_xmit(struct ppp_channel + + struct rtable *rt; + struct net_device *tdev; ++ struct net_device *pptp_dev; + struct iphdr *iph; + int max_headroom; ++ int pptp_ifindex; ++ int ret; + + if (sk_pppox(po)->sk_state & PPPOX_DEAD) + goto tx_error; +@@ -258,7 +336,32 @@ static int pptp_xmit(struct ppp_channel + ip_select_ident(net, skb, NULL); + ip_send_check(iph); + +- ip_local_out(net, skb->sk, skb); ++ pptp_ifindex = ppp_dev_index(chan); ++ ++ /* set incoming interface as the ppp interface */ ++ if (skb->skb_iif) ++ skb->skb_iif = pptp_ifindex; ++ ++ /* If the PPTP GRE seq number offload module is not enabled yet ++ * then sends all PPTP GRE packets through linux network stack ++ */ ++ if (!opt->pptp_offload_mode) { ++ ip_local_out(net, skb->sk, skb); ++ return 1; ++ } ++ ++ pptp_dev = dev_get_by_index(&init_net, pptp_ifindex); ++ if (!pptp_dev) ++ goto tx_error; ++ ++ /* If PPTP offload module is enabled then forward all PPTP GRE ++ * packets to PPTP GRE offload module ++ */ ++ ret = pptp_client_skb_xmit(skb, pptp_dev); ++ dev_put(pptp_dev); ++ if (ret < 0) ++ goto tx_error; ++ + return 1; + + tx_error: +@@ -314,6 +417,13 @@ static int pptp_rcv_core(struct sock *sk + goto drop; + + payload = skb->data + headersize; ++ ++ /* If offload is enabled, we expect the offload module ++ * to handle PPTP GRE sequence number checks ++ */ ++ if (opt->pptp_offload_mode) ++ goto allow_packet; ++ + /* check for expected sequence number */ + if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) { + if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) && +@@ -371,6 +481,7 @@ static int pptp_rcv(struct sk_buff *skb) + if (po) { + skb_dst_drop(skb); + nf_reset_ct(skb); ++ skb->skb_iif = ppp_dev_index(&po->chan); + return sk_receive_skb(sk_pppox(po), skb, 0); + } + drop: +@@ -473,7 +584,7 @@ static int pptp_connect(struct socket *s + + opt->dst_addr = sp->sa_addr.pptp; + sk->sk_state |= PPPOX_CONNECTED; +- ++ opt->pptp_offload_mode = false; + end: + release_sock(sk); + return error; +@@ -603,9 +714,169 @@ static int pptp_ppp_ioctl(struct ppp_cha + return err; + } + ++/* pptp_channel_addressing_get() ++ * Return PPTP channel specific addressing information. ++ */ ++void pptp_channel_addressing_get(struct pptp_opt *opt, struct ppp_channel *chan) ++{ ++ struct sock *sk; ++ struct pppox_sock *po; ++ ++ if (!opt) ++ return; ++ ++ sk = (struct sock *)chan->private; ++ if (!sk) ++ return; ++ ++ sock_hold(sk); ++ ++ /* This is very unlikely, but check the socket is connected state */ ++ if (unlikely(sock_flag(sk, SOCK_DEAD) || ++ !(sk->sk_state & PPPOX_CONNECTED))) { ++ sock_put(sk); ++ return; ++ } ++ ++ po = pppox_sk(sk); ++ memcpy(opt, &po->proto.pptp, sizeof(struct pptp_opt)); ++ sock_put(sk); ++} ++EXPORT_SYMBOL(pptp_channel_addressing_get); ++ ++/* pptp_session_find() ++ * Search and return a PPTP session info based on peer callid and IP ++ * address. The function accepts the parameters in network byte order. ++ */ ++int pptp_session_find(struct pptp_opt *opt, __be16 peer_call_id, ++ __be32 peer_ip_addr) ++{ ++ if (!opt) ++ return -EINVAL; ++ ++ return lookup_session_dst(opt, ntohs(peer_call_id), peer_ip_addr); ++} ++EXPORT_SYMBOL(pptp_session_find); ++ ++/* pptp_session_find_by_src_callid() ++ * Search and return a PPTP session info based on src callid and IP ++ * address. The function accepts the parameters in network byte order. ++ */ ++int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id, ++ __be32 daddr, __be32 saddr) ++{ ++ if (!opt) ++ return -EINVAL; ++ ++ return lookup_session_src(opt, ntohs(src_call_id), daddr, saddr); ++} ++EXPORT_SYMBOL(pptp_session_find_by_src_callid); ++ ++ /* Function to change the offload mode true/false for a PPTP session */ ++static int pptp_set_offload_mode(bool accel_mode, ++ __be16 peer_call_id, __be32 peer_ip_addr) ++{ ++ struct pppox_sock *sock; ++ int i = 1; ++ ++ rcu_read_lock(); ++ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) { ++ sock = rcu_dereference(callid_sock[i]); ++ if (!sock) ++ continue; ++ ++ if (sock->proto.pptp.dst_addr.call_id == peer_call_id && ++ sock->proto.pptp.dst_addr.sin_addr.s_addr == peer_ip_addr) { ++ sock_hold(sk_pppox(sock)); ++ sock->proto.pptp.pptp_offload_mode = accel_mode; ++ sock_put(sk_pppox(sock)); ++ rcu_read_unlock(); ++ return 0; ++ } ++ } ++ rcu_read_unlock(); ++ return -EINVAL; ++} ++ ++/* Enable the PPTP session offload flag */ ++int pptp_session_enable_offload_mode(__be16 peer_call_id, __be32 peer_ip_addr) ++{ ++ return pptp_set_offload_mode(true, peer_call_id, peer_ip_addr); ++} ++EXPORT_SYMBOL(pptp_session_enable_offload_mode); ++ ++/* Disable the PPTP session offload flag */ ++int pptp_session_disable_offload_mode(__be16 peer_call_id, __be32 peer_ip_addr) ++{ ++ return pptp_set_offload_mode(false, peer_call_id, peer_ip_addr); ++} ++EXPORT_SYMBOL(pptp_session_disable_offload_mode); ++ ++/* Register the offload callback function on behalf of the module which ++ * will own the sequence and acknowledgment number updates for all ++ * PPTP GRE packets. All PPTP GRE packets are then transmitted to this ++ * module after encapsulation in order to ensure the correct seq/ack ++ * fields are set in the packets before transmission. This is required ++ * when PPTP flows are offloaded to acceleration engines, in-order to ++ * ensure consistency in sequence and ack numbers between PPTP control ++ * (PPP LCP) and data packets ++ */ ++int pptp_register_gre_seq_offload_callback(pptp_gre_seq_offload_callback_t ++ pptp_gre_offload_cb) ++{ ++ pptp_gre_seq_offload_callback_t pptp_gre_offload_cb_f; ++ ++ rcu_read_lock(); ++ pptp_gre_offload_cb_f = rcu_dereference(pptp_gre_offload_xmit_cb); ++ ++ if (pptp_gre_offload_cb_f) { ++ rcu_read_unlock(); ++ return -1; ++ } ++ ++ rcu_assign_pointer(pptp_gre_offload_xmit_cb, pptp_gre_offload_cb); ++ rcu_read_unlock(); ++ return 0; ++} ++EXPORT_SYMBOL(pptp_register_gre_seq_offload_callback); ++ ++/* Unregister the PPTP GRE packets sequence number offload callback */ ++void pptp_unregister_gre_seq_offload_callback(void) ++{ ++ rcu_assign_pointer(pptp_gre_offload_xmit_cb, NULL); ++} ++EXPORT_SYMBOL(pptp_unregister_gre_seq_offload_callback); ++ ++/* pptp_hold_chan() */ ++static void pptp_hold_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_hold(sk); ++} ++ ++/* pptp_release_chan() */ ++static void pptp_release_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_put(sk); ++} ++ ++/* pptp_get_channel_protocol() ++ * Return the protocol type of the PPTP over PPP protocol ++ */ ++static int pptp_get_channel_protocol(struct ppp_channel *chan) ++{ ++ return PX_PROTO_PPTP; ++} ++ + static const struct ppp_channel_ops pptp_chan_ops = { + .start_xmit = pptp_xmit, + .ioctl = pptp_ppp_ioctl, ++ .get_channel_protocol = pptp_get_channel_protocol, ++ .hold = pptp_hold_chan, ++ .release = pptp_release_chan, + }; + + static struct proto pptp_sk_proto __read_mostly = { diff --git a/6.1/target/linux/qualcommax/patches-6.1/0603-4-qca-nss-clients-add-iptunnel-support.patch b/6.1/target/linux/qualcommax/patches-6.1/0603-4-qca-nss-clients-add-iptunnel-support.patch new file mode 100644 index 000000000..928510087 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0603-4-qca-nss-clients-add-iptunnel-support.patch @@ -0,0 +1,77 @@ +--- a/include/net/ip6_tunnel.h ++++ b/include/net/ip6_tunnel.h +@@ -36,6 +36,7 @@ struct __ip6_tnl_parm { + __u8 proto; /* tunnel protocol */ + __u8 encap_limit; /* encapsulation limit for tunnel */ + __u8 hop_limit; /* hop limit for tunnel */ ++ __u8 draft03; /* FMR using draft03 of map-e - QCA NSS Clients Support */ + bool collect_md; + __be32 flowinfo; /* traffic class and flowlabel for tunnel */ + __u32 flags; /* tunnel flags */ +--- a/include/net/ip_tunnels.h ++++ b/include/net/ip_tunnels.h +@@ -553,4 +553,9 @@ static inline void ip_tunnel_info_opts_s + + #endif /* CONFIG_INET */ + ++/* QCA NSS Clients Support - Start */ ++void ipip6_update_offload_stats(struct net_device *dev, void *ptr); ++void ip6_update_offload_stats(struct net_device *dev, void *ptr); ++/* QCA NSS Clients Support - End */ ++ + #endif /* __NET_IP_TUNNELS_H */ +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -2398,6 +2398,26 @@ nla_put_failure: + return -EMSGSIZE; + } + ++/* QCA NSS Client Support - Start */ ++/* ++ * Update offload stats ++ */ ++void ip6_update_offload_stats(struct net_device *dev, void *ptr) ++{ ++ struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0); ++ const struct pcpu_sw_netstats *offload_stats = ++ (struct pcpu_sw_netstats *)ptr; ++ ++ u64_stats_update_begin(&tstats->syncp); ++ u64_stats_add(&tstats->tx_packets, u64_stats_read(&offload_stats->tx_packets)); ++ u64_stats_add(&tstats->tx_bytes, u64_stats_read(&offload_stats->tx_bytes)); ++ u64_stats_add(&tstats->rx_packets, u64_stats_read(&offload_stats->rx_packets)); ++ u64_stats_add(&tstats->rx_bytes, u64_stats_read(&offload_stats->rx_bytes)); ++ u64_stats_update_end(&tstats->syncp); ++} ++EXPORT_SYMBOL(ip6_update_offload_stats); ++/* QCA NSS Client Support - End */ ++ + struct net *ip6_tnl_get_link_net(const struct net_device *dev) + { + struct ip6_tnl *tunnel = netdev_priv(dev); +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -1733,6 +1733,23 @@ nla_put_failure: + return -EMSGSIZE; + } + ++/* QCA NSS Clients Support - Start */ ++void ipip6_update_offload_stats(struct net_device *dev, void *ptr) ++{ ++ struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0); ++ const struct pcpu_sw_netstats *offload_stats = ++ (struct pcpu_sw_netstats *)ptr; ++ ++ u64_stats_update_begin(&tstats->syncp); ++ u64_stats_add(&tstats->tx_packets, u64_stats_read(&offload_stats->tx_packets)); ++ u64_stats_add(&tstats->tx_bytes, u64_stats_read(&offload_stats->tx_bytes)); ++ u64_stats_add(&tstats->rx_packets, u64_stats_read(&offload_stats->rx_packets)); ++ u64_stats_add(&tstats->rx_bytes, u64_stats_read(&offload_stats->rx_bytes)); ++ u64_stats_update_end(&tstats->syncp); ++} ++EXPORT_SYMBOL(ipip6_update_offload_stats); ++/* QCA NSS Clients Support - End */ ++ + static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, + [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, diff --git a/6.1/target/linux/qualcommax/patches-6.1/0603-5-qca-nss-clients-add-vxlan-support.patch b/6.1/target/linux/qualcommax/patches-6.1/0603-5-qca-nss-clients-add-vxlan-support.patch new file mode 100644 index 000000000..4704b7d24 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0603-5-qca-nss-clients-add-vxlan-support.patch @@ -0,0 +1,103 @@ +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -71,6 +71,20 @@ static inline bool vxlan_collect_metadat + ip_tunnel_collect_metadata(); + } + ++ATOMIC_NOTIFIER_HEAD(vxlan_fdb_notifier_list); ++ ++void vxlan_fdb_register_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_register(&vxlan_fdb_notifier_list, nb); ++} ++EXPORT_SYMBOL(vxlan_fdb_register_notify); ++ ++void vxlan_fdb_unregister_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_unregister(&vxlan_fdb_notifier_list, nb); ++} ++EXPORT_SYMBOL(vxlan_fdb_unregister_notify); ++ + #if IS_ENABLED(CONFIG_IPV6) + static int vxlan_nla_get_addr(union vxlan_addr *ip, struct nlattr *nla) + { +@@ -307,6 +321,7 @@ static void __vxlan_fdb_notify(struct vx + { + struct net *net = dev_net(vxlan->dev); + struct sk_buff *skb; ++ struct vxlan_fdb_event vfe; + int err = -ENOBUFS; + + skb = nlmsg_new(vxlan_nlmsg_size(), GFP_ATOMIC); +@@ -322,6 +337,10 @@ static void __vxlan_fdb_notify(struct vx + } + + rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); ++ vfe.dev = vxlan->dev; ++ vfe.rdst = rd; ++ ether_addr_copy(vfe.eth_addr, fdb->eth_addr); ++ atomic_notifier_call_chain(&vxlan_fdb_notifier_list, type, (void *)&vfe); + return; + errout: + if (err < 0) +@@ -488,6 +507,18 @@ static struct vxlan_fdb *vxlan_find_mac( + return f; + } + ++/* Find and update age of fdb entry corresponding to MAC. */ ++void vxlan_fdb_update_mac(struct vxlan_dev *vxlan, const u8 *mac, uint32_t vni) ++{ ++ u32 hash_index; ++ ++ hash_index = fdb_head_index(vxlan, mac, vni); ++ spin_lock_bh(&vxlan->hash_lock[hash_index]); ++ vxlan_find_mac(vxlan, mac, vni); ++ spin_unlock_bh(&vxlan->hash_lock[hash_index]); ++} ++EXPORT_SYMBOL(vxlan_fdb_update_mac); ++ + /* caller should hold vxlan->hash_lock */ + static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f, + union vxlan_addr *ip, __be16 port, +@@ -2658,6 +2689,9 @@ static void vxlan_xmit_one(struct sk_buf + goto out_unlock; + } + ++ /* Reset the skb_iif to Tunnels interface index */ ++ skb->skb_iif = dev->ifindex; ++ + tos = ip_tunnel_ecn_encap(tos, old_iph, skb); + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), +@@ -2729,6 +2763,9 @@ static void vxlan_xmit_one(struct sk_buf + if (err < 0) + goto tx_error; + ++ /* Reset the skb_iif to Tunnels interface index */ ++ skb->skb_iif = dev->ifindex; ++ + udp_tunnel6_xmit_skb(ndst, sock6->sock->sk, skb, dev, + &local_ip.sin6.sin6_addr, + &dst->sin6.sin6_addr, tos, ttl, +--- a/include/net/vxlan.h ++++ b/include/net/vxlan.h +@@ -344,6 +344,19 @@ struct vxlan_dev { + VXLAN_F_COLLECT_METADATA | \ + VXLAN_F_VNIFILTER) + ++/* ++ * Application data for fdb notifier event ++ */ ++struct vxlan_fdb_event { ++ struct net_device *dev; ++ struct vxlan_rdst *rdst; ++ u8 eth_addr[ETH_ALEN]; ++}; ++ ++extern void vxlan_fdb_register_notify(struct notifier_block *nb); ++extern void vxlan_fdb_unregister_notify(struct notifier_block *nb); ++extern void vxlan_fdb_update_mac(struct vxlan_dev *vxlan, const u8 *mac, uint32_t vni); ++ + struct net_device *vxlan_dev_create(struct net *net, const char *name, + u8 name_assign_type, struct vxlan_config *conf); + diff --git a/6.1/target/linux/qualcommax/patches-6.1/0603-6-qca-nss-clients-add-l2tp-offloading-support.patch b/6.1/target/linux/qualcommax/patches-6.1/0603-6-qca-nss-clients-add-l2tp-offloading-support.patch new file mode 100644 index 000000000..4032eb3c2 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0603-6-qca-nss-clients-add-l2tp-offloading-support.patch @@ -0,0 +1,368 @@ +--- a/include/linux/ppp_channel.h ++++ b/include/linux/ppp_channel.h +@@ -61,6 +61,51 @@ struct ppp_channel { + }; + + #ifdef __KERNEL__ ++/* Call this to obtain the underlying protocol of the PPP channel, ++ * e.g. PX_PROTO_OE ++ */ ++extern int ppp_channel_get_protocol(struct ppp_channel *); ++ ++/* Call this to hold a channel */ ++extern bool ppp_channel_hold(struct ppp_channel *); ++ ++/* Call this to release a hold you have upon a channel */ ++extern void ppp_channel_release(struct ppp_channel *); ++ ++/* Release hold on PPP channels */ ++extern void ppp_release_channels(struct ppp_channel *channels[], ++ unsigned int chan_sz); ++ ++/* Test if ppp xmit lock is locked */ ++extern bool ppp_is_xmit_locked(struct net_device *dev); ++ ++/* Call this get protocol version */ ++extern int ppp_channel_get_proto_version(struct ppp_channel *); ++ ++/* Get the device index associated with a channel, or 0, if none */ ++extern int ppp_dev_index(struct ppp_channel *); ++ ++/* Hold PPP channels for the PPP device */ ++extern int ppp_hold_channels(struct net_device *dev, ++ struct ppp_channel *channels[], ++ unsigned int chan_sz); ++extern int __ppp_hold_channels(struct net_device *dev, ++ struct ppp_channel *channels[], ++ unsigned int chan_sz); ++ ++/* Test if the ppp device is a multi-link ppp device */ ++extern int ppp_is_multilink(struct net_device *dev); ++extern int __ppp_is_multilink(struct net_device *dev); ++ ++/* Update statistics of the PPP net_device by incrementing related ++ * statistics field value with corresponding parameter ++ */ ++extern void ppp_update_stats(struct net_device *dev, unsigned long rx_packets, ++ unsigned long rx_bytes, unsigned long tx_packets, ++ unsigned long tx_bytes, unsigned long rx_errors, ++ unsigned long tx_errors, unsigned long rx_dropped, ++ unsigned long tx_dropped); ++ + /* Called by the channel when it can send some more data. */ + extern void ppp_output_wakeup(struct ppp_channel *); + +@@ -148,5 +193,17 @@ extern void ppp_update_stats(struct net_ + * that ppp_unregister_channel returns. + */ + ++/* QCA NSS Clients Support - Start */ ++/* PPP channel connection event types */ ++#define PPP_CHANNEL_DISCONNECT 0 ++#define PPP_CHANNEL_CONNECT 1 ++ ++/* Register the PPP channel connect notifier */ ++extern void ppp_channel_connection_register_notify(struct notifier_block *nb); ++ ++/* Unregister the PPP channel connect notifier */ ++extern void ppp_channel_connection_unregister_notify(struct notifier_block *nb); ++/* QCA NSS Clients Support - End */ ++ + #endif /* __KERNEL__ */ + #endif +--- a/include/linux/if_pppol2tp.h ++++ b/include/linux/if_pppol2tp.h +@@ -12,4 +12,30 @@ + #include + #include + ++/* QCA NSS ECM support - Start */ ++/* ++ * Holds L2TP channel info ++ */ ++struct pppol2tp_common_addr { ++ int tunnel_version; /* v2 or v3 */ ++ __u32 local_tunnel_id, remote_tunnel_id; /* tunnel id */ ++ __u32 local_session_id, remote_session_id; /* session id */ ++ struct sockaddr_in local_addr, remote_addr; /* ip address and port */ ++}; ++ ++/* ++ * L2TP channel operations ++ */ ++struct pppol2tp_channel_ops { ++ struct ppp_channel_ops ops; /* ppp channel ops */ ++}; ++ ++/* ++ * exported function which calls pppol2tp channel's get addressing ++ * function ++ */ ++extern int pppol2tp_channel_addressing_get(struct ppp_channel *, ++ struct pppol2tp_common_addr *); ++/* QCA NSS ECM support - End */ ++ + #endif +--- a/net/l2tp/l2tp_ppp.c ++++ b/net/l2tp/l2tp_ppp.c +@@ -123,9 +123,17 @@ struct pppol2tp_session { + }; + + static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb); +- +-static const struct ppp_channel_ops pppol2tp_chan_ops = { +- .start_xmit = pppol2tp_xmit, ++static int pppol2tp_get_channel_protocol(struct ppp_channel *); ++static int pppol2tp_get_channel_protocol_ver(struct ppp_channel *); ++static void pppol2tp_hold_chan(struct ppp_channel *); ++static void pppol2tp_release_chan(struct ppp_channel *); ++ ++static const struct pppol2tp_channel_ops pppol2tp_chan_ops = { ++ .ops.start_xmit = pppol2tp_xmit, ++ .ops.get_channel_protocol = pppol2tp_get_channel_protocol, ++ .ops.get_channel_protocol_ver = pppol2tp_get_channel_protocol_ver, ++ .ops.hold = pppol2tp_hold_chan, ++ .ops.release = pppol2tp_release_chan, + }; + + static const struct proto_ops pppol2tp_ops; +@@ -373,6 +381,13 @@ static int pppol2tp_xmit(struct ppp_chan + skb->data[0] = PPP_ALLSTATIONS; + skb->data[1] = PPP_UI; + ++ /* QCA NSS ECM support - start */ ++ /* set incoming interface as the ppp interface */ ++ if ((skb->protocol == htons(ETH_P_IP)) || ++ (skb->protocol == htons(ETH_P_IPV6))) ++ skb->skb_iif = ppp_dev_index(chan); ++ /* QCA NSS ECM support - End */ ++ + local_bh_disable(); + l2tp_xmit_skb(session, skb); + local_bh_enable(); +@@ -818,7 +833,7 @@ static int pppol2tp_connect(struct socke + po->chan.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ; + + po->chan.private = sk; +- po->chan.ops = &pppol2tp_chan_ops; ++ po->chan.ops = (struct ppp_channel_ops *)&pppol2tp_chan_ops.ops; + po->chan.mtu = pppol2tp_tunnel_mtu(tunnel); + + error = ppp_register_net_channel(sock_net(sk), &po->chan); +@@ -1732,6 +1747,109 @@ static void __exit pppol2tp_exit(void) + unregister_pernet_device(&pppol2tp_net_ops); + } + ++/* QCA NSS ECM support - Start */ ++/* pppol2tp_hold_chan() */ ++static void pppol2tp_hold_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_hold(sk); ++} ++ ++/* pppol2tp_release_chan() */ ++static void pppol2tp_release_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_put(sk); ++} ++ ++/* pppol2tp_get_channel_protocol() ++ * Return the protocol type of the L2TP over PPP protocol ++ */ ++static int pppol2tp_get_channel_protocol(struct ppp_channel *chan) ++{ ++ return PX_PROTO_OL2TP; ++} ++ ++/* pppol2tp_get_channel_protocol_ver() ++ * Return the protocol version of the L2TP over PPP protocol ++ */ ++static int pppol2tp_get_channel_protocol_ver(struct ppp_channel *chan) ++{ ++ struct sock *sk; ++ struct l2tp_session *session; ++ struct l2tp_tunnel *tunnel; ++ int version = 0; ++ ++ if (chan && chan->private) ++ sk = (struct sock *)chan->private; ++ else ++ return -1; ++ ++ /* Get session and tunnel contexts from the socket */ ++ session = pppol2tp_sock_to_session(sk); ++ if (!session) ++ return -1; ++ ++ tunnel = session->tunnel; ++ if (!tunnel) { ++ sock_put(sk); ++ return -1; ++ } ++ ++ version = tunnel->version; ++ ++ sock_put(sk); ++ ++ return version; ++} ++ ++/* pppol2tp_get_addressing() */ ++static int pppol2tp_get_addressing(struct ppp_channel *chan, ++ struct pppol2tp_common_addr *addr) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ struct l2tp_session *session; ++ struct l2tp_tunnel *tunnel; ++ struct inet_sock *isk = NULL; ++ int err = -ENXIO; ++ ++ /* Get session and tunnel contexts from the socket */ ++ session = pppol2tp_sock_to_session(sk); ++ if (!session) ++ return err; ++ ++ tunnel = session->tunnel; ++ if (!tunnel) { ++ sock_put(sk); ++ return err; ++ } ++ isk = inet_sk(tunnel->sock); ++ ++ addr->local_tunnel_id = tunnel->tunnel_id; ++ addr->remote_tunnel_id = tunnel->peer_tunnel_id; ++ addr->local_session_id = session->session_id; ++ addr->remote_session_id = session->peer_session_id; ++ ++ addr->local_addr.sin_port = isk->inet_sport; ++ addr->remote_addr.sin_port = isk->inet_dport; ++ addr->local_addr.sin_addr.s_addr = isk->inet_saddr; ++ addr->remote_addr.sin_addr.s_addr = isk->inet_daddr; ++ ++ sock_put(sk); ++ return 0; ++} ++ ++/* pppol2tp_channel_addressing_get() */ ++int pppol2tp_channel_addressing_get(struct ppp_channel *chan, ++ struct pppol2tp_common_addr *addr) ++{ ++ return pppol2tp_get_addressing(chan, addr); ++} ++EXPORT_SYMBOL(pppol2tp_channel_addressing_get); ++/* QCA NSS ECM support - End */ ++ + module_init(pppol2tp_init); + module_exit(pppol2tp_exit); + +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3743,6 +3743,32 @@ int ppp_is_multilink(struct net_device * + } + EXPORT_SYMBOL(ppp_is_multilink); + ++/* __ppp_is_multilink() ++ * Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 ++ * if the device is not PPP. Caller should acquire ppp_lock before calling ++ * this function ++ */ ++int __ppp_is_multilink(struct net_device *dev) ++{ ++ struct ppp *ppp; ++ unsigned int flags; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ flags = ppp->flags; ++ ++ if (flags & SC_MULTILINK) ++ return 1; ++ ++ return 0; ++} ++EXPORT_SYMBOL(__ppp_is_multilink); ++ + /* ppp_channel_get_protocol() + * Call this to obtain the underlying protocol of the PPP channel, + * e.g. PX_PROTO_OE +@@ -3881,6 +3907,59 @@ int ppp_hold_channels(struct net_device + } + EXPORT_SYMBOL(ppp_hold_channels); + ++/* __ppp_hold_channels() ++ * Returns the PPP channels of the PPP device, storing each one into ++ * channels[]. ++ * ++ * channels[] has chan_sz elements. ++ * This function returns the number of channels stored, up to chan_sz. ++ * It will return < 0 if the device is not PPP. ++ * ++ * You MUST release the channels using ppp_release_channels(). ++ */ ++int __ppp_hold_channels(struct net_device *dev, struct ppp_channel *channels[], ++ unsigned int chan_sz) ++{ ++ struct ppp *ppp; ++ int c; ++ struct channel *pch; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ ++ c = 0; ++ list_for_each_entry(pch, &ppp->channels, clist) { ++ struct ppp_channel *chan; ++ ++ if (!pch->chan) { ++ /* Channel is going / gone away */ ++ continue; ++ } ++ ++ if (c == chan_sz) { ++ /* No space to record channel */ ++ return c; ++ } ++ ++ /* Hold the channel, if supported */ ++ chan = pch->chan; ++ if (!chan->ops->hold) ++ continue; ++ ++ chan->ops->hold(chan); ++ ++ /* Record the channel */ ++ channels[c++] = chan; ++ } ++ return c; ++} ++EXPORT_SYMBOL(__ppp_hold_channels); ++ + /* ppp_release_channels() + * Releases channels + */ +--- a/net/l2tp/l2tp_core.h ++++ b/net/l2tp/l2tp_core.h +@@ -235,6 +235,9 @@ struct l2tp_session *l2tp_session_get_by + void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session, + struct l2tp_stats *stats); + ++void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session, ++ struct l2tp_stats *stats); ++ + /* Tunnel and session lifetime management. + * Creation of a new instance is a two-step process: create, then register. + * Destruction is triggered using the *_delete functions, and completes asynchronously. diff --git a/6.1/target/linux/qualcommax/patches-6.1/0603-7-qca-nss-clients-iptunnel-lock-this-cpu.patch b/6.1/target/linux/qualcommax/patches-6.1/0603-7-qca-nss-clients-iptunnel-lock-this-cpu.patch new file mode 100644 index 000000000..faba23d86 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0603-7-qca-nss-clients-iptunnel-lock-this-cpu.patch @@ -0,0 +1,22 @@ +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -2404,7 +2404,7 @@ nla_put_failure: + */ + void ip6_update_offload_stats(struct net_device *dev, void *ptr) + { +- struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0); ++ struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); + const struct pcpu_sw_netstats *offload_stats = + (struct pcpu_sw_netstats *)ptr; + +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -1736,7 +1736,7 @@ nla_put_failure: + /* QCA NSS Clients Support - Start */ + void ipip6_update_offload_stats(struct net_device *dev, void *ptr) + { +- struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0); ++ struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); + const struct pcpu_sw_netstats *offload_stats = + (struct pcpu_sw_netstats *)ptr; + diff --git a/6.1/target/linux/qualcommax/patches-6.1/0603-8-qca-nss-clients-add-tls-mgr-support.patch b/6.1/target/linux/qualcommax/patches-6.1/0603-8-qca-nss-clients-add-tls-mgr-support.patch new file mode 100644 index 000000000..0499e237f --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0603-8-qca-nss-clients-add-tls-mgr-support.patch @@ -0,0 +1,24 @@ +--- /dev/null ++++ b/include/uapi/linux/tlshdr.h +@@ -0,0 +1,21 @@ ++#ifndef _UAPI_LINUX_TLSHDR_H ++#define _UAPI_LINUX_TLSHDR_H ++ ++#include ++ ++struct tlshdr { ++ __u8 type; ++ __be16 version; ++ __be16 len; ++} __attribute__((packed)); ++ ++#define TLSHDR_REC_TYPE_CCS 20 /* TLS packet is change cipher specification */ ++#define TLSHDR_REC_TYPE_ALERT 21 /* TLS packet is Alert */ ++#define TLSHDR_REC_TYPE_HANDSHAKE 22 /* TLS packet is Handshake */ ++#define TLSHDR_REC_TYPE_DATA 23 /* TLS packet is Application data */ ++ ++#define TLSHDR_VERSION_1_1 0x0302 /* TLS Header Version(tls 1.1) */ ++#define TLSHDR_VERSION_1_2 0x0303 /* TLS Header Version(tls 1.2) */ ++#define TLSHDR_VERSION_1_3 0x0304 /* TLS Header Version(tls 1.3) */ ++ ++#endif /* _UAPI_LINUX_TLSHDR_H */ diff --git a/6.1/target/linux/qualcommax/patches-6.1/0604-1-qca-add-mcs-support.patch b/6.1/target/linux/qualcommax/patches-6.1/0604-1-qca-add-mcs-support.patch new file mode 100644 index 000000000..7035383ac --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0604-1-qca-add-mcs-support.patch @@ -0,0 +1,876 @@ +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -281,4 +281,17 @@ extern br_get_dst_hook_t __rcu *br_get_d + extern struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br); + /* QCA NSS bridge-mgr support - End */ + ++/* QCA qca-mcs support - Start */ ++typedef struct net_bridge_port *br_get_dst_hook_t(const struct net_bridge_port *src, ++ struct sk_buff **skb); ++extern br_get_dst_hook_t __rcu *br_get_dst_hook; ++ ++typedef int (br_multicast_handle_hook_t)(const struct net_bridge_port *src, ++ struct sk_buff *skb); ++extern br_multicast_handle_hook_t __rcu *br_multicast_handle_hook; ++ ++typedef void (br_notify_hook_t)(int group, int event, const void *ptr); ++extern br_notify_hook_t __rcu *br_notify_hook; ++/* QCA qca-mcs support - End */ ++ + #endif +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -232,6 +232,8 @@ static void fdb_notify(struct net_bridge + kfree_skb(skb); + goto errout; + } ++ ++ __br_notify(RTNLGRP_NEIGH, type, fdb); /* QCA qca-mcs support */ + rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); + return; + errout: +@@ -298,6 +300,7 @@ struct net_bridge_fdb_entry *br_fdb_find + { + return fdb_find_rcu(&br->fdb_hash_tbl, addr, vid); + } ++EXPORT_SYMBOL_GPL(br_fdb_find_rcu); /* QCA qca-mcs support */ + + /* When a static FDB entry is added, the mac address from the entry is + * added to the bridge private HW address list and all required ports +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -853,6 +853,7 @@ void br_manage_promisc(struct net_bridge + int nbp_backup_change(struct net_bridge_port *p, struct net_device *backup_dev); + + /* br_input.c */ ++int br_pass_frame_up(struct sk_buff *skb); /* QCA qca-mcs support */ + int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb); + rx_handler_func_t *br_get_rx_handler(const struct net_device *dev); + +@@ -2178,4 +2179,14 @@ struct nd_msg *br_is_nd_neigh_msg(struct + #define __br_get(__hook, __default, __args ...) \ + (__hook ? (__hook(__args)) : (__default)) + /* QCA NSS ECM support - End */ ++ ++/* QCA qca-mcs support - Start */ ++static inline void __br_notify(int group, int type, const void *data) ++{ ++ br_notify_hook_t *notify_hook = rcu_dereference(br_notify_hook); ++ ++ if (notify_hook) ++ notify_hook(group, type, data); ++} ++/* QCA qca-mcs support - End */ + #endif +--- a/net/bridge/br_netlink.c ++++ b/net/bridge/br_netlink.c +@@ -640,6 +640,7 @@ void br_info_notify(int event, const str + kfree_skb(skb); + goto errout; + } ++ __br_notify(RTNLGRP_LINK, event, port); /* QCA qca-mcs support */ + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); + return; + errout: +--- a/net/bridge/br.c ++++ b/net/bridge/br.c +@@ -467,6 +467,12 @@ static void __exit br_deinit(void) + br_fdb_fini(); + } + ++/* QCA qca-mcs support - Start */ ++/* Hook for bridge event notifications */ ++br_notify_hook_t __rcu *br_notify_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_notify_hook); ++/* QCA qca-mcs support - End */ ++ + module_init(br_init) + module_exit(br_deinit) + MODULE_LICENSE("GPL"); +--- a/net/bridge/br_device.c ++++ b/net/bridge/br_device.c +@@ -82,6 +82,13 @@ netdev_tx_t br_dev_xmit(struct sk_buff * + if (is_broadcast_ether_addr(dest)) { + br_flood(br, skb, BR_PKT_BROADCAST, false, true); + } else if (is_multicast_ether_addr(dest)) { ++ /* QCA qca-mcs support - Start */ ++ br_multicast_handle_hook_t *multicast_handle_hook = ++ rcu_dereference(br_multicast_handle_hook); ++ if (!__br_get(multicast_handle_hook, true, NULL, skb)) ++ goto out; ++ /* QCA qca-mcs support - End */ ++ + if (unlikely(netpoll_tx_running(dev))) { + br_flood(br, skb, BR_PKT_MULTICAST, false, true); + goto out; +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -30,7 +30,17 @@ br_netif_receive_skb(struct net *net, st + return netif_receive_skb(skb); + } + +-static int br_pass_frame_up(struct sk_buff *skb) ++/* QCA qca-mcs support - Start */ ++/* Hook for external Multicast handler */ ++br_multicast_handle_hook_t __rcu *br_multicast_handle_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_multicast_handle_hook); ++ ++/* Hook for external forwarding logic */ ++br_get_dst_hook_t __rcu *br_get_dst_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_get_dst_hook); ++/* QCA qca-mcs support - End */ ++ ++int br_pass_frame_up(struct sk_buff *skb) + { + struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev; + struct net_bridge *br = netdev_priv(brdev); +@@ -69,6 +79,7 @@ static int br_pass_frame_up(struct sk_bu + dev_net(indev), NULL, skb, indev, NULL, + br_netif_receive_skb); + } ++EXPORT_SYMBOL_GPL(br_pass_frame_up); /* QCA qca-mcs support */ + + /* note: already called with rcu_read_lock */ + int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb) +@@ -82,6 +93,11 @@ int br_handle_frame_finish(struct net *n + struct net_bridge_mcast *brmctx; + struct net_bridge_vlan *vlan; + struct net_bridge *br; ++ /* QCA qca-mcs support - Start */ ++ br_multicast_handle_hook_t *multicast_handle_hook; ++ struct net_bridge_port *pdst = NULL; ++ br_get_dst_hook_t *get_dst_hook = rcu_dereference(br_get_dst_hook); ++ /* QCA qca-mcs support - End */ + u16 vid = 0; + u8 state; + +@@ -158,6 +174,12 @@ int br_handle_frame_finish(struct net *n + + switch (pkt_type) { + case BR_PKT_MULTICAST: ++ /* QCA qca-mcs support - Start */ ++ multicast_handle_hook = rcu_dereference(br_multicast_handle_hook); ++ if (!__br_get(multicast_handle_hook, true, p, skb)) ++ goto out; ++ /* QCA qca-mcs support - End */ ++ + mdst = br_mdb_get(brmctx, skb, vid); + if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && + br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) { +@@ -173,8 +195,15 @@ int br_handle_frame_finish(struct net *n + } + break; + case BR_PKT_UNICAST: +- dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid); +- break; ++ /* QCA qca-mcs support - Start */ ++ pdst = __br_get(get_dst_hook, NULL, p, &skb); ++ if (pdst) { ++ if (!skb) ++ goto out; ++ } else { ++ /* QCA qca-mcs support - End */ ++ dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid); ++ } + default: + break; + } +@@ -189,6 +218,13 @@ int br_handle_frame_finish(struct net *n + dst->used = now; + br_forward(dst->dst, skb, local_rcv, false); + } else { ++ /* QCA qca-mcs support - Start */ ++ if (pdst) { ++ br_forward(pdst, skb, local_rcv, false); ++ goto out; ++ } ++ /* QCA qca-mcs support - End */ ++ + if (!mcast_hit) + br_flood(br, skb, pkt_type, local_rcv, false); + else +--- a/include/linux/mroute.h ++++ b/include/linux/mroute.h +@@ -85,4 +85,44 @@ struct rtmsg; + int ipmr_get_route(struct net *net, struct sk_buff *skb, + __be32 saddr, __be32 daddr, + struct rtmsg *rtm, u32 portid); ++ ++/* QCA ECM qca-mcs support - Start */ ++#define IPMR_MFC_EVENT_UPDATE 1 ++#define IPMR_MFC_EVENT_DELETE 2 ++ ++/* ++ * Callback to registered modules in the event of updates to a multicast group ++ */ ++typedef void (*ipmr_mfc_event_offload_callback_t)(__be32 origin, __be32 group, ++ u32 max_dest_dev, ++ u32 dest_dev_idx[], ++ u8 op); ++ ++/* ++ * Register the callback used to inform offload modules when updates occur to ++ * MFC. The callback is registered by offload modules ++ */ ++extern bool ipmr_register_mfc_event_offload_callback( ++ ipmr_mfc_event_offload_callback_t mfc_offload_cb); ++ ++/* ++ * De-Register the callback used to inform offload modules when updates occur ++ * to MFC ++ */ ++extern void ipmr_unregister_mfc_event_offload_callback(void); ++ ++/* ++ * Find the destination interface list, given a multicast group and source ++ */ ++extern int ipmr_find_mfc_entry(struct net *net, __be32 origin, __be32 group, ++ u32 max_dst_cnt, u32 dest_dev[]); ++ ++/* ++ * Out-of-band multicast statistics update for flows that are offloaded from ++ * Linux ++ */ ++extern int ipmr_mfc_stats_update(struct net *net, __be32 origin, __be32 group, ++ u64 pkts_in, u64 bytes_in, ++ u64 pkts_out, u64 bytes_out); ++/* QCA ECM qca-mcs support - End */ + #endif +--- a/include/linux/mroute6.h ++++ b/include/linux/mroute6.h +@@ -110,4 +110,47 @@ static inline int ip6mr_sk_done(struct s + return 0; + } + #endif ++ ++/* QCA qca-mcs support - Start */ ++#define IP6MR_MFC_EVENT_UPDATE 1 ++#define IP6MR_MFC_EVENT_DELETE 2 ++ ++/* ++ * Callback to registered modules in the event of updates to a multicast group ++ */ ++typedef void (*ip6mr_mfc_event_offload_callback_t)(struct in6_addr *origin, ++ struct in6_addr *group, ++ u32 max_dest_dev, ++ u32 dest_dev_idx[], ++ uint8_t op); ++ ++/* ++ * Register the callback used to inform offload modules when updates occur ++ * to MFC. The callback is registered by offload modules ++ */ ++extern bool ip6mr_register_mfc_event_offload_callback( ++ ip6mr_mfc_event_offload_callback_t mfc_offload_cb); ++ ++/* ++ * De-Register the callback used to inform offload modules when updates occur ++ * to MFC ++ */ ++extern void ip6mr_unregister_mfc_event_offload_callback(void); ++ ++/* ++ * Find the destination interface list given a multicast group and source ++ */ ++extern int ip6mr_find_mfc_entry(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, u32 max_dst_cnt, ++ u32 dest_dev[]); ++ ++/* ++ * Out-of-band multicast statistics update for flows that are offloaded from ++ * Linux ++ */ ++extern int ip6mr_mfc_stats_update(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, uint64_t pkts_in, ++ uint64_t bytes_in, uint64_t pkts_out, ++ uint64_t bytes_out); ++/* QCA qca-mcs support - End */ + #endif +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -89,6 +89,9 @@ static struct net_device *vif_dev_read(c + /* Special spinlock for queue of unresolved entries */ + static DEFINE_SPINLOCK(mfc_unres_lock); + ++/* spinlock for offload */ ++static DEFINE_SPINLOCK(lock); /* QCA ECM qca-mcs support */ ++ + /* We return to original Alan's scheme. Hash table of resolved + * entries is changed only in process context and protected + * with weak lock mrt_lock. Queue of unresolved entries is protected +@@ -112,6 +115,9 @@ static void mroute_netlink_event(struct + static void igmpmsg_netlink_event(const struct mr_table *mrt, struct sk_buff *pkt); + static void mroute_clean_tables(struct mr_table *mrt, int flags); + static void ipmr_expire_process(struct timer_list *t); ++static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt, __be32 origin, ++ __be32 mcastgrp); ++static ipmr_mfc_event_offload_callback_t __rcu ipmr_mfc_event_offload_callback; /* QCA ECM qca-mcs support */ + + #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES + #define ipmr_for_each_table(mrt, net) \ +@@ -223,6 +229,80 @@ static int ipmr_rule_fill(struct fib_rul + return 0; + } + ++/* QCA ECM qca-mcs support - Start */ ++/* ipmr_sync_entry_update() ++ * Call the registered offload callback to report an update to a multicast ++ * route entry. The callback receives the list of destination interfaces and ++ * the interface count ++ */ ++static void ipmr_sync_entry_update(struct mr_table *mrt, ++ struct mfc_cache *cache) ++{ ++ int vifi, dest_if_count = 0; ++ u32 dest_dev[MAXVIFS]; ++ __be32 origin; ++ __be32 group; ++ ipmr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ memset(dest_dev, 0, sizeof(dest_dev)); ++ ++ origin = cache->mfc_origin; ++ group = cache->mfc_mcastgrp; ++ ++ spin_lock(&mrt_lock); ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ if (dest_if_count == MAXVIFS) { ++ spin_unlock(&mrt_lock); ++ return; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ return; ++ } ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ spin_unlock(&mrt_lock); ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(group, origin, dest_if_count, dest_dev, ++ IPMR_MFC_EVENT_UPDATE); ++ rcu_read_unlock(); ++} ++ ++/* ipmr_sync_entry_delete() ++ * Call the registered offload callback to inform of a multicast route entry ++ * delete event ++ */ ++static void ipmr_sync_entry_delete(u32 origin, u32 group) ++{ ++ ipmr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(group, origin, 0, NULL, IPMR_MFC_EVENT_DELETE); ++ rcu_read_unlock(); ++} ++/* QCA ECM qca-mcs support - End */ ++ + static const struct fib_rules_ops __net_initconst ipmr_rules_ops_template = { + .family = RTNL_FAMILY_IPMR, + .rule_size = sizeof(struct ipmr_rule), +@@ -236,6 +316,156 @@ static const struct fib_rules_ops __net_ + .owner = THIS_MODULE, + }; + ++/* QCA ECM qca-mcs support - Start */ ++/* ipmr_register_mfc_event_offload_callback() ++ * Register the IPv4 Multicast update offload callback with IPMR ++ */ ++bool ipmr_register_mfc_event_offload_callback( ++ ipmr_mfc_event_offload_callback_t mfc_offload_cb) ++{ ++ ipmr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback); ++ ++ if (offload_update_cb_f) { ++ rcu_read_unlock(); ++ return false; ++ } ++ rcu_read_unlock(); ++ ++ spin_lock(&lock); ++ rcu_assign_pointer(ipmr_mfc_event_offload_callback, mfc_offload_cb); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++ return true; ++} ++EXPORT_SYMBOL(ipmr_register_mfc_event_offload_callback); ++ ++/* ipmr_unregister_mfc_event_offload_callback() ++ * De-register the IPv4 Multicast update offload callback with IPMR ++ */ ++void ipmr_unregister_mfc_event_offload_callback(void) ++{ ++ spin_lock(&lock); ++ rcu_assign_pointer(ipmr_mfc_event_offload_callback, NULL); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL(ipmr_unregister_mfc_event_offload_callback); ++ ++/* ipmr_find_mfc_entry() ++ * Returns destination interface list for a particular multicast flow, and ++ * the number of interfaces in the list ++ */ ++int ipmr_find_mfc_entry(struct net *net, __be32 origin, __be32 group, ++ u32 max_dest_cnt, u32 dest_dev[]) ++{ ++ int vifi, dest_if_count = 0; ++ struct mr_table *mrt; ++ struct mfc_cache *cache; ++ ++ mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); ++ if (!mrt) ++ return -ENOENT; ++ ++ rcu_read_lock(); ++ cache = ipmr_cache_find(mrt, origin, group); ++ if (!cache) { ++ rcu_read_unlock(); ++ return -ENOENT; ++ } ++ ++ spin_lock(&mrt_lock); ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ ++ /* We have another valid destination interface entry. Check if ++ * the number of the destination interfaces for the route is ++ * exceeding the size of the array given to us ++ */ ++ if (dest_if_count == max_dest_cnt) { ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ ++ return dest_if_count; ++} ++EXPORT_SYMBOL(ipmr_find_mfc_entry); ++ ++/* ipmr_mfc_stats_update() ++ * Update the MFC/VIF statistics for offloaded flows ++ */ ++int ipmr_mfc_stats_update(struct net *net, __be32 origin, __be32 group, ++ u64 pkts_in, u64 bytes_in, ++ u64 pkts_out, u64 bytes_out) ++{ ++ int vif, vifi; ++ struct mr_table *mrt; ++ struct mfc_cache *cache; ++ ++ mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); ++ if (!mrt) ++ return -ENOENT; ++ ++ rcu_read_lock(); ++ cache = ipmr_cache_find(mrt, origin, group); ++ if (!cache) { ++ rcu_read_unlock(); ++ return -ENOENT; ++ } ++ ++ vif = cache->_c.mfc_parent; ++ ++ spin_lock(&mrt_lock); ++ if (!VIF_EXISTS(mrt, vif)) { ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ ++ mrt->vif_table[vif].pkt_in += pkts_in; ++ mrt->vif_table[vif].bytes_in += bytes_in; ++ cache->_c.mfc_un.res.pkt += pkts_out; ++ cache->_c.mfc_un.res.bytes += bytes_out; ++ ++ for (vifi = cache->_c.mfc_un.res.minvif; ++ vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if ((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255)) { ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ mrt->vif_table[vifi].pkt_out += pkts_out; ++ mrt->vif_table[vifi].bytes_out += bytes_out; ++ } ++ } ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ ++ return 0; ++} ++EXPORT_SYMBOL(ipmr_mfc_stats_update); ++/* QCA ECM qca-mcs support - End */ ++ + static int __net_init ipmr_rules_init(struct net *net) + { + struct fib_rules_ops *ops; +@@ -1191,6 +1421,10 @@ static int ipmr_mfc_delete(struct mr_tab + call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, c, mrt->id); + mroute_netlink_event(mrt, c, RTM_DELROUTE); + mr_cache_put(&c->_c); ++ /* QCA ECM qca-mcs support - Start */ ++ /* Inform offload modules of the delete event */ ++ ipmr_sync_entry_delete(c->mfc_origin, c->mfc_mcastgrp); ++ /* QCA ECM qca-mcs support - End */ + + return 0; + } +@@ -1221,6 +1455,10 @@ static int ipmr_mfc_add(struct net *net, + call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, c, + mrt->id); + mroute_netlink_event(mrt, c, RTM_NEWROUTE); ++ /* QCA ECM qca-mcs support - Start */ ++ /* Inform offload modules of the update event */ ++ ipmr_sync_entry_update(mrt, c); ++ /* QCA ECM qca-mcs support - End */ + return 0; + } + +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -74,6 +74,9 @@ static struct net_device *vif_dev_read(c + /* Special spinlock for queue of unresolved entries */ + static DEFINE_SPINLOCK(mfc_unres_lock); + ++/* Spinlock for offload */ ++static DEFINE_SPINLOCK(lock); /* QCA qca-mcs support */ ++ + /* We return to original Alan's scheme. Hash table of resolved + entries is changed only in process context and protected + with weak lock mrt_lock. Queue of unresolved entries is protected +@@ -101,6 +104,13 @@ static int ip6mr_rtm_dumproute(struct sk + struct netlink_callback *cb); + static void mroute_clean_tables(struct mr_table *mrt, int flags); + static void ipmr_expire_process(struct timer_list *t); ++/* QCA qca-mcs support - Start */ ++static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt, ++ const struct in6_addr *origin, ++ const struct in6_addr *mcastgrp); ++static ip6mr_mfc_event_offload_callback_t __rcu ++ ip6mr_mfc_event_offload_callback; ++/* QCA qca-mcs support - End */ + + #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES + #define ip6mr_for_each_table(mrt, net) \ +@@ -375,6 +385,84 @@ static struct mfc6_cache_cmp_arg ip6mr_m + .mf6c_mcastgrp = IN6ADDR_ANY_INIT, + }; + ++/* QCA qca-mcs support - Start */ ++/* ip6mr_sync_entry_update() ++ * Call the registered offload callback to report an update to a multicast ++ * route entry. The callback receives the list of destination interfaces and ++ * the interface count ++ */ ++static void ip6mr_sync_entry_update(struct mr_table *mrt, ++ struct mfc6_cache *cache) ++{ ++ int vifi, dest_if_count = 0; ++ u32 dest_dev[MAXMIFS]; ++ struct in6_addr mc_origin, mc_group; ++ ip6mr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ memset(dest_dev, 0, sizeof(dest_dev)); ++ ++ spin_lock(&mrt_lock); ++ ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ ++ if (dest_if_count == MAXMIFS) { ++ spin_unlock(&mrt_lock); ++ return; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ return; ++ } ++ ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ ++ memcpy(&mc_origin, &cache->mf6c_origin, sizeof(struct in6_addr)); ++ memcpy(&mc_group, &cache->mf6c_mcastgrp, sizeof(struct in6_addr)); ++ spin_unlock(&mrt_lock); ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(&mc_group, &mc_origin, dest_if_count, dest_dev, ++ IP6MR_MFC_EVENT_UPDATE); ++ rcu_read_unlock(); ++} ++ ++/* ip6mr_sync_entry_delete() ++ * Call the registered offload callback to inform of a multicast route entry ++ * delete event ++ */ ++static void ip6mr_sync_entry_delete(struct in6_addr *mc_origin, ++ struct in6_addr *mc_group) ++{ ++ ip6mr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(mc_group, mc_origin, 0, NULL, ++ IP6MR_MFC_EVENT_DELETE); ++ rcu_read_unlock(); ++} ++/* QCA qca-mcs support - End */ ++ + static struct mr_table_ops ip6mr_mr_table_ops = { + .rht_params = &ip6mr_rht_params, + .cmparg_any = &ip6mr_mr_table_ops_cmparg_any, +@@ -697,6 +785,151 @@ static int call_ip6mr_mfc_entry_notifier + &mfc->_c, tb_id, &net->ipv6.ipmr_seq); + } + ++/* QCA qca-mcs support - Start */ ++/* ip6mr_register_mfc_event_offload_callback() ++ * Register the IPv6 multicast update callback for offload modules ++ */ ++bool ip6mr_register_mfc_event_offload_callback( ++ ip6mr_mfc_event_offload_callback_t mfc_offload_cb) ++{ ++ ip6mr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback); ++ ++ if (offload_update_cb_f) { ++ rcu_read_unlock(); ++ return false; ++ } ++ rcu_read_unlock(); ++ ++ spin_lock(&lock); ++ rcu_assign_pointer(ip6mr_mfc_event_offload_callback, mfc_offload_cb); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++ return true; ++} ++EXPORT_SYMBOL(ip6mr_register_mfc_event_offload_callback); ++ ++/* ip6mr_unregister_mfc_event_offload_callback() ++ * De-register the IPv6 multicast update callback for offload modules ++ */ ++void ip6mr_unregister_mfc_event_offload_callback(void) ++{ ++ spin_lock(&lock); ++ rcu_assign_pointer(ip6mr_mfc_event_offload_callback, NULL); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL(ip6mr_unregister_mfc_event_offload_callback); ++ ++/* ip6mr_find_mfc_entry() ++ * Return the destination interface list for a particular multicast flow, and ++ * the number of interfaces in the list ++ */ ++int ip6mr_find_mfc_entry(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, u32 max_dest_cnt, ++ u32 dest_dev[]) ++{ ++ int vifi, dest_if_count = 0; ++ struct mr_table *mrt; ++ struct mfc6_cache *cache; ++ ++ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); ++ if (!mrt) ++ return -ENOENT; ++ ++ spin_lock(&mrt_lock); ++ cache = ip6mr_cache_find(mrt, origin, group); ++ if (!cache) { ++ spin_unlock(&mrt_lock); ++ return -ENOENT; ++ } ++ ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ ++ /* We have another valid destination interface entry. Check if ++ * the number of the destination interfaces for the route is ++ * exceeding the size of the array given to us ++ */ ++ if (dest_if_count == max_dest_cnt) { ++ spin_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ spin_unlock(&mrt_lock); ++ ++ return dest_if_count; ++} ++EXPORT_SYMBOL(ip6mr_find_mfc_entry); ++ ++/* ip6mr_mfc_stats_update() ++ * Update the MFC/VIF statistics for offloaded flows ++ */ ++int ip6mr_mfc_stats_update(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, u64 pkts_in, ++ u64 bytes_in, uint64_t pkts_out, ++ u64 bytes_out) ++{ ++ int vif, vifi; ++ struct mr_table *mrt; ++ struct mfc6_cache *cache; ++ ++ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); ++ ++ if (!mrt) ++ return -ENOENT; ++ ++ spin_lock(&mrt_lock); ++ cache = ip6mr_cache_find(mrt, origin, group); ++ if (!cache) { ++ spin_unlock(&mrt_lock); ++ return -ENOENT; ++ } ++ ++ vif = cache->_c.mfc_parent; ++ ++ if (!VIF_EXISTS(mrt, vif)) { ++ spin_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ ++ mrt->vif_table[vif].pkt_in += pkts_in; ++ mrt->vif_table[vif].bytes_in += bytes_in; ++ cache->_c.mfc_un.res.pkt += pkts_out; ++ cache->_c.mfc_un.res.bytes += bytes_out; ++ ++ for (vifi = cache->_c.mfc_un.res.minvif; ++ vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if ((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255)) { ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ mrt->vif_table[vifi].pkt_out += pkts_out; ++ mrt->vif_table[vifi].bytes_out += bytes_out; ++ } ++ } ++ ++ spin_unlock(&mrt_lock); ++ return 0; ++} ++EXPORT_SYMBOL(ip6mr_mfc_stats_update); ++/* QCA qca-mcs support - End */ ++ + /* Delete a VIF entry */ + static int mif6_delete(struct mr_table *mrt, int vifi, int notify, + struct list_head *head) +@@ -1221,6 +1454,7 @@ static int ip6mr_mfc_delete(struct mr_ta + int parent) + { + struct mfc6_cache *c; ++ struct in6_addr mc_origin, mc_group; /* QCA qca-mcs support */ + + /* The entries are added/deleted only under RTNL */ + rcu_read_lock(); +@@ -1229,6 +1463,11 @@ static int ip6mr_mfc_delete(struct mr_ta + rcu_read_unlock(); + if (!c) + return -ENOENT; ++ ++ /* QCA qca-mcs support - Start */ ++ memcpy(&mc_origin, &c->mf6c_origin, sizeof(struct in6_addr)); ++ memcpy(&mc_group, &c->mf6c_mcastgrp, sizeof(struct in6_addr)); ++ /* QCA qca-mcs support - End */ + rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params); + list_del_rcu(&c->_c.list); + +@@ -1236,6 +1475,11 @@ static int ip6mr_mfc_delete(struct mr_ta + FIB_EVENT_ENTRY_DEL, c, mrt->id); + mr6_netlink_event(mrt, c, RTM_DELROUTE); + mr_cache_put(&c->_c); ++ /* QCA qca-mcs support - Start */ ++ /* Inform offload modules of the delete event */ ++ ip6mr_sync_entry_delete(&mc_origin, &mc_group); ++ /* QCA qca-mcs support - End */ ++ + return 0; + } + +@@ -1457,6 +1701,10 @@ static int ip6mr_mfc_add(struct net *net + call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, + c, mrt->id); + mr6_netlink_event(mrt, c, RTM_NEWROUTE); ++ /* QCA qca-mcs support - Start */ ++ /* Inform offload modules of the update event */ ++ ip6mr_sync_entry_update(mrt, c); ++ /* QCA qca-mcs support - End */ + return 0; + } + diff --git a/6.1/target/linux/qualcommax/patches-6.1/0605-1-qca-nss-cfi-support.patch b/6.1/target/linux/qualcommax/patches-6.1/0605-1-qca-nss-cfi-support.patch new file mode 100644 index 000000000..67e85a18f --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0605-1-qca-nss-cfi-support.patch @@ -0,0 +1,111 @@ +--- a/crypto/authenc.c ++++ b/crypto/authenc.c +@@ -417,6 +417,8 @@ static int crypto_authenc_create(struct + enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + ++ inst->alg.base.cra_flags |= (auth_base->cra_flags | ++ enc->base.cra_flags) & CRYPTO_ALG_NOSUPP_SG; + inst->alg.base.cra_priority = enc->base.cra_priority * 10 + + auth_base->cra_priority; + inst->alg.base.cra_blocksize = enc->base.cra_blocksize; +--- a/include/linux/crypto.h ++++ b/include/linux/crypto.h +@@ -101,6 +101,11 @@ + #define CRYPTO_NOLOAD 0x00008000 + + /* ++ * Set this flag if algorithm does not support SG list transforms ++ */ ++#define CRYPTO_ALG_NOSUPP_SG 0x0000c000 ++ ++/* + * The algorithm may allocate memory during request processing, i.e. during + * encryption, decryption, or hashing. Users can request an algorithm with this + * flag unset if they can't handle memory allocation failures. +--- a/net/ipv4/esp4.c ++++ b/net/ipv4/esp4.c +@@ -658,6 +658,7 @@ static int esp_output(struct xfrm_state + struct ip_esp_hdr *esph; + struct crypto_aead *aead; + struct esp_info esp; ++ bool nosupp_sg; + + esp.inplace = true; + +@@ -669,6 +670,11 @@ static int esp_output(struct xfrm_state + aead = x->data; + alen = crypto_aead_authsize(aead); + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ return -ENOMEM; ++ } ++ + esp.tfclen = 0; + if (x->tfcpad) { + struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); +@@ -890,6 +896,7 @@ static int esp_input(struct xfrm_state * + u8 *iv; + struct scatterlist *sg; + int err = -EINVAL; ++ bool nosupp_sg; + + if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) + goto out; +@@ -897,6 +904,12 @@ static int esp_input(struct xfrm_state * + if (elen <= 0) + goto out; + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ + assoclen = sizeof(struct ip_esp_hdr); + seqhilen = 0; + +--- a/net/ipv6/esp6.c ++++ b/net/ipv6/esp6.c +@@ -696,6 +696,7 @@ static int esp6_output(struct xfrm_state + struct ip_esp_hdr *esph; + struct crypto_aead *aead; + struct esp_info esp; ++ bool nosupp_sg; + + esp.inplace = true; + +@@ -707,6 +708,11 @@ static int esp6_output(struct xfrm_state + aead = x->data; + alen = crypto_aead_authsize(aead); + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ return -ENOMEM; ++ } ++ + esp.tfclen = 0; + if (x->tfcpad) { + struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); +@@ -934,6 +940,7 @@ static int esp6_input(struct xfrm_state + __be32 *seqhi; + u8 *iv; + struct scatterlist *sg; ++ bool nosupp_sg; + + if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) { + ret = -EINVAL; +@@ -945,6 +952,12 @@ static int esp6_input(struct xfrm_state + goto out; + } + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ + assoclen = sizeof(struct ip_esp_hdr); + seqhilen = 0; + diff --git a/6.1/target/linux/qualcommax/patches-6.1/0611-ipv6-Fix-null-pointer-dereference-in-ipv6-output.patch b/6.1/target/linux/qualcommax/patches-6.1/0611-ipv6-Fix-null-pointer-dereference-in-ipv6-output.patch new file mode 100644 index 000000000..608ab7f2b --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0611-ipv6-Fix-null-pointer-dereference-in-ipv6-output.patch @@ -0,0 +1,80 @@ +From eee3a7956b943dd3e23a74fbb5bfe89405eb0782 Mon Sep 17 00:00:00 2001 +From: Andrea Righi +Date: Mon, 6 Dec 2021 17:34:47 +0100 +Subject: UBUNTU: SAUCE: ipv6: fix NULL pointer dereference in ip6_output() + +It is possible to trigger a NULL pointer dereference by running the srv6 +net kselftest (tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh): + +[ 249.051216] BUG: kernel NULL pointer dereference, address: 0000000000000378 +[ 249.052331] #PF: supervisor read access in kernel mode +[ 249.053137] #PF: error_code(0x0000) - not-present page +[ 249.053960] PGD 0 P4D 0 +[ 249.054376] Oops: 0000 [#1] PREEMPT SMP NOPTI +[ 249.055083] CPU: 1 PID: 21 Comm: ksoftirqd/1 Tainted: G E 5.16.0-rc4 #2 +[ 249.056328] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014 +[ 249.057632] RIP: 0010:ip6_forward+0x53c/0xab0 +[ 249.058354] Code: 49 c7 44 24 20 00 00 00 00 48 83 e0 fe 48 8b 40 30 48 3d 70 b2 b5 81 0f 85 b5 04 00 00 e8 7c f2 ff ff 41 89 c5 e9 17 01 00 00 <44> 8b 93 78 03 00 00 45 85 d2 0f 85 92 fb ff ff 49 8b 54 24 10 48 +[ 249.061274] RSP: 0018:ffffc900000cbb30 EFLAGS: 00010246 +[ 249.062042] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff8881051d3400 +[ 249.063141] RDX: ffff888104bda000 RSI: 00000000000002c0 RDI: 0000000000000000 +[ 249.064264] RBP: ffffc900000cbbc8 R08: 0000000000000000 R09: 0000000000000000 +[ 249.065376] R10: 0000000000000040 R11: 0000000000000000 R12: ffff888103409800 +[ 249.066498] R13: ffff8881051d3410 R14: ffff888102725280 R15: ffff888103525000 +[ 249.067619] FS: 0000000000000000(0000) GS:ffff88813bc80000(0000) knlGS:0000000000000000 +[ 249.068881] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 249.069777] CR2: 0000000000000378 CR3: 0000000104980000 CR4: 0000000000750ee0 +[ 249.070907] PKRU: 55555554 +[ 249.071337] Call Trace: +[ 249.071730] +[ 249.072070] ? debug_smp_processor_id+0x17/0x20 +[ 249.072807] seg6_input_core+0x2bb/0x2d0 +[ 249.073436] ? _raw_spin_unlock_irqrestore+0x29/0x40 +[ 249.074225] seg6_input+0x3b/0x130 +[ 249.074768] lwtunnel_input+0x5e/0xa0 +[ 249.075357] ip_rcv+0x17b/0x190 +[ 249.075867] ? update_load_avg+0x82/0x600 +[ 249.076514] __netif_receive_skb_one_core+0x86/0xa0 +[ 249.077231] __netif_receive_skb+0x15/0x60 +[ 249.077843] process_backlog+0x97/0x160 +[ 249.078389] __napi_poll+0x31/0x170 +[ 249.078912] net_rx_action+0x229/0x270 +[ 249.079506] __do_softirq+0xef/0x2ed +[ 249.080085] run_ksoftirqd+0x37/0x50 +[ 249.080663] smpboot_thread_fn+0x193/0x230 +[ 249.081312] kthread+0x17a/0x1a0 +[ 249.081847] ? smpboot_register_percpu_thread+0xe0/0xe0 +[ 249.082677] ? set_kthread_struct+0x50/0x50 +[ 249.083340] ret_from_fork+0x22/0x30 +[ 249.083926] +[ 249.090295] ---[ end trace 1998d7ba5965a365 ]--- + +It looks like commit 0857d6f8c759 ("ipv6: When forwarding count rx stats +on the orig netdev") tries to determine the right netdev to account the +rx stats, but in this particular case it's failing and the netdev is +NULL. + +Fallback to the previous method of determining the netdev interface (via +skb->dev) to account the rx stats when the orig netdev can't be +determined. + +Fixes: 0857d6f8c759 ("ipv6: When forwarding count rx stats on the orig netdev") +Signed-off-by: Andrea Righi +(cherry picked from https://lore.kernel.org/lkml/20211206163447.991402-1-andrea.righi@canonical.com/T/#u) +Signed-off-by: Andrea Righi +--- + net/ipv6/ip6_output.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -492,6 +492,9 @@ int ip6_forward(struct sk_buff *skb) + u32 mtu; + + idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif)); ++ if (unlikely(!idev)) ++ idev = __in6_dev_get_safely(skb->dev); ++ + if (net->ipv6.devconf_all->forwarding == 0) + goto error; + diff --git a/6.1/target/linux/qualcommax/patches-6.1/0905-ipq8074-add-blsp1-i2c4.patch b/6.1/target/linux/qualcommax/patches-6.1/0905-ipq8074-add-blsp1-i2c4.patch new file mode 100644 index 000000000..7d6a60b81 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/0905-ipq8074-add-blsp1-i2c4.patch @@ -0,0 +1,25 @@ +diff -uprN a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi +--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi 2023-06-22 18:11:32.910676000 -0700 ++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi 2023-07-26 21:43:58.269612521 -0700 +@@ -750,6 +750,21 @@ + status = "disabled"; + }; + ++ blsp1_i2c4: i2c@78b8000 { ++ compatible = "qcom,i2c-qup-v2.2.1"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x078b8000 0x600>; ++ interrupts = ; ++ clocks = <&gcc GCC_BLSP1_QUP4_I2C_APPS_CLK>, ++ <&gcc GCC_BLSP1_AHB_CLK>; ++ clock-names = "core", "iface"; ++ clock-frequency = <100000>; ++ dmas = <&blsp_dma 18>, <&blsp_dma 19>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ + blsp1_i2c5: i2c@78b9000 { + compatible = "qcom,i2c-qup-v2.2.1"; + #address-cells = <1>; diff --git a/6.1/target/linux/qualcommax/patches-6.1/9990-1-qca-skb_recycler-support.patch b/6.1/target/linux/qualcommax/patches-6.1/9990-1-qca-skb_recycler-support.patch new file mode 100644 index 000000000..899e0a2b5 --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/9990-1-qca-skb_recycler-support.patch @@ -0,0 +1,412 @@ +--- a/include/linux/cpuhotplug.h ++++ b/include/linux/cpuhotplug.h +@@ -94,6 +94,7 @@ enum cpuhp_state { + CPUHP_RADIX_DEAD, + CPUHP_PAGE_ALLOC, + CPUHP_NET_DEV_DEAD, ++ CPUHP_SKB_RECYCLER_DEAD, + CPUHP_PCI_XGENE_DEAD, + CPUHP_IOMMU_IOVA_DEAD, + CPUHP_LUSTRE_CFS_DEAD, +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -1240,7 +1240,7 @@ static inline void kfree_skb_list(struct sk_buff *segs) + kfree_skb_list_reason(segs, SKB_DROP_REASON_NOT_SPECIFIED); + } + +-#ifdef CONFIG_TRACEPOINTS ++#ifdef CONFIG_SKB_RECYCLER + void consume_skb(struct sk_buff *skb); + #else + static inline void consume_skb(struct sk_buff *skb) +@@ -1252,6 +1252,8 @@ static inline void consume_skb(struct sk_buff *skb) + void __consume_stateless_skb(struct sk_buff *skb); + void __kfree_skb(struct sk_buff *skb); + extern struct kmem_cache *skbuff_head_cache; ++extern void kfree_skbmem(struct sk_buff *skb); ++extern void skb_release_data(struct sk_buff *skb); + + void kfree_skb_partial(struct sk_buff *skb, bool head_stolen); + bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from, +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -332,6 +332,27 @@ config NET_FLOW_LIMIT + with many clients some protection against DoS by a single (spoofed) + flow that greatly exceeds average workload. + ++config SKB_RECYCLER ++ bool "Generic skb recycling" ++ default y ++ help ++ SKB_RECYCLER is used to implement RX-to-RX skb recycling. ++ This config enables the recycling scheme for bridging and ++ routing workloads. It can reduce skbuff freeing or ++ reallocation overhead. ++ ++config SKB_RECYCLER_MULTI_CPU ++ bool "Cross-CPU recycling for CPU-locked workloads" ++ depends on SMP && SKB_RECYCLER ++ default n ++ ++config ALLOC_SKB_PAGE_FRAG_DISABLE ++ bool "Disable page fragment based skbuff payload allocations" ++ depends on !SKB_RECYCLER ++ default n ++ help ++ Disable page fragment based allocations for skbuff payloads. ++ + menu "Network testing" + + config NET_PKTGEN +--- a/net/core/Makefile ++++ b/net/core/Makefile +@@ -40,3 +40,4 @@ obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o + obj-$(CONFIG_BPF_SYSCALL) += sock_map.o + obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o + obj-$(CONFIG_OF) += of_net.o ++obj-$(CONFIG_SKB_RECYCLER) += skbuff_recycle.o +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -5974,10 +5974,16 @@ static int process_backlog(struct napi_struct *napi, int quota) + + napi->weight = READ_ONCE(dev_rx_weight); + while (again) { +- struct sk_buff *skb; ++ struct sk_buff *skb, *next_skb; + + while ((skb = __skb_dequeue(&sd->process_queue))) { + rcu_read_lock(); ++ ++ next_skb = skb_peek(&sd->process_queue); ++ if (likely(next_skb)) { ++ prefetch(next_skb->data); ++ } ++ + __netif_receive_skb(skb); + rcu_read_unlock(); + input_queue_head_incr(sd); +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -84,6 +84,33 @@ + #include "dev.h" + #include "sock_destructor.h" + ++struct kmem_cache *skb_data_cache; ++ ++/* ++ * For low memory profile, NSS_SKB_FIXED_SIZE_2K is enabled and ++ * CONFIG_SKB_RECYCLER is disabled. For premium and enterprise profile ++ * CONFIG_SKB_RECYCLER is enabled and NSS_SKB_FIXED_SIZE_2K is disabled. ++ * Irrespective of NSS_SKB_FIXED_SIZE_2K enabled/disabled, the ++ * CONFIG_SKB_RECYCLER and __LP64__ determines the value of SKB_DATA_CACHE_SIZE ++ */ ++#if defined(CONFIG_SKB_RECYCLER) ++/* ++ * 2688 for 64bit arch, 2624 for 32bit arch ++ */ ++#define SKB_DATA_CACHE_SIZE (SKB_DATA_ALIGN(SKB_RECYCLE_SIZE + NET_SKB_PAD) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) ++#else ++/* ++ * 2368 for 64bit arch, 2176 for 32bit arch ++ */ ++#if defined(__LP64__) ++#define SKB_DATA_CACHE_SIZE ((SKB_DATA_ALIGN(1984 + NET_SKB_PAD)) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) ++#else ++#define SKB_DATA_CACHE_SIZE ((SKB_DATA_ALIGN(1856 + NET_SKB_PAD)) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) ++#endif ++#endif ++ ++#include "skbuff_recycle.h" ++ + struct kmem_cache *skbuff_head_cache __ro_after_init; + static struct kmem_cache *skbuff_fclone_cache __ro_after_init; + #ifdef CONFIG_SKB_EXTENSIONS +@@ -426,32 +453,46 @@ EXPORT_SYMBOL(napi_build_skb); + * memory is free + */ + static void *kmalloc_reserve(unsigned int *size, gfp_t flags, int node, +- bool *pfmemalloc) +-{ +- bool ret_pfmemalloc = false; +- size_t obj_size; +- void *obj; ++ bool *pfmemalloc) ++ { ++ void *obj; ++ bool ret_pfmemalloc = false; ++ unsigned int obj_size = *size; ++ ++ if (obj_size > SZ_2K && obj_size <= SKB_DATA_CACHE_SIZE) { ++ obj = kmem_cache_alloc_node(skb_data_cache, ++ flags | __GFP_NOMEMALLOC | __GFP_NOWARN, ++ node); ++ *size = SKB_DATA_CACHE_SIZE; ++ if (obj || !(gfp_pfmemalloc_allowed(flags))) ++ goto out; + +- obj_size = SKB_HEAD_ALIGN(*size); ++ /* Try again but now we are using pfmemalloc reserves */ ++ ret_pfmemalloc = true; ++ obj = kmem_cache_alloc_node(skb_data_cache, flags, node); ++ goto out; ++ } + + obj_size = kmalloc_size_roundup(obj_size); +- /* The following cast might truncate high-order bits of obj_size, this ++ ++ /* ++ * The following cast might truncate high-order bits of obj_size, this + * is harmless because kmalloc(obj_size >= 2^32) will fail anyway. + */ + *size = (unsigned int)obj_size; + +- /* +- * Try a regular allocation, when that fails and we're not entitled +- * to the reserves, fail. +- */ ++ /* ++ * Try a regular allocation, when that fails and we're not entitled ++ * to the reserves, fail. ++ */ + obj = kmalloc_node_track_caller(obj_size, +- flags | __GFP_NOMEMALLOC | __GFP_NOWARN, +- node); +- if (obj || !(gfp_pfmemalloc_allowed(flags))) +- goto out; ++ flags | __GFP_NOMEMALLOC | __GFP_NOWARN, ++ node); ++ if (obj || !(gfp_pfmemalloc_allowed(flags))) ++ goto out; + +- /* Try again but now we are using pfmemalloc reserves */ +- ret_pfmemalloc = true; ++ /* Try again but now we are using pfmemalloc reserves */ ++ ret_pfmemalloc = true; + obj = kmalloc_node_track_caller(obj_size, flags, node); + + out: +@@ -513,10 +554,12 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, + * aligned memory blocks, unless SLUB/SLAB debug is enabled. + * Both skb->head and skb_shared_info are cache line aligned. + */ ++ size = SKB_DATA_ALIGN(size); ++ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + data = kmalloc_reserve(&size, gfp_mask, node, &pfmemalloc); + if (unlikely(!data)) + goto nodata; +- /* kmalloc_size_roundup() might give us more room than requested. ++ /* kmalloc_reserve(size) might give us more room than requested. + * Put skb_shared_info exactly at the end of allocated zone, + * to allow max possible filling before reallocation. + */ +@@ -551,7 +594,7 @@ EXPORT_SYMBOL(__alloc_skb); + /** + * __netdev_alloc_skb - allocate an skbuff for rx on a specific device + * @dev: network device to receive on +- * @len: length to allocate ++ * @length: length to allocate + * @gfp_mask: get_free_pages mask, passed to alloc_skb + * + * Allocate a new &sk_buff and assign it a usage count of one. The +@@ -561,29 +604,53 @@ EXPORT_SYMBOL(__alloc_skb); + * + * %NULL is returned if there is no free memory. + */ +-struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len, +- gfp_t gfp_mask) ++struct sk_buff *__netdev_alloc_skb(struct net_device *dev, ++ unsigned int length, gfp_t gfp_mask) + { +- struct page_frag_cache *nc; + struct sk_buff *skb; ++ unsigned int len = length; ++ ++#ifdef CONFIG_SKB_RECYCLER ++ skb = skb_recycler_alloc(dev, length); ++ if (likely(skb)) ++ return skb; ++ ++ len = SKB_RECYCLE_SIZE; ++ if (unlikely(length > SKB_RECYCLE_SIZE)) ++ len = length; ++ ++ skb = __alloc_skb(len + NET_SKB_PAD, gfp_mask, ++ SKB_ALLOC_RX, NUMA_NO_NODE); ++ if (!skb) ++ goto skb_fail; ++ goto skb_success; ++#else ++ struct page_frag_cache *nc; + bool pfmemalloc; ++ bool page_frag_alloc_enable = true; + void *data; + + len += NET_SKB_PAD; + ++ ++#ifdef CONFIG_ALLOC_SKB_PAGE_FRAG_DISABLE ++ page_frag_alloc_enable = false; ++#endif + /* If requested length is either too small or too big, + * we use kmalloc() for skb->head allocation. + */ + if (len <= SKB_WITH_OVERHEAD(1024) || + len > SKB_WITH_OVERHEAD(PAGE_SIZE) || +- (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) { ++ (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA)) || ++ !page_frag_alloc_enable) { + skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE); + if (!skb) + goto skb_fail; + goto skb_success; + } + +- len = SKB_HEAD_ALIGN(len); ++ len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); ++ len = SKB_DATA_ALIGN(len); + + if (sk_memalloc_socks()) + gfp_mask |= __GFP_MEMALLOC; +@@ -612,6 +679,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len, + if (pfmemalloc) + skb->pfmemalloc = 1; + skb->head_frag = 1; ++#endif + + skb_success: + skb_reserve(skb, NET_SKB_PAD); +@@ -682,7 +750,8 @@ struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len, + data = page_frag_alloc_1k(&nc->page_small, gfp_mask); + pfmemalloc = NAPI_SMALL_PAGE_PFMEMALLOC(nc->page_small); + } else { +- len = SKB_HEAD_ALIGN(len); ++ len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); ++ len = SKB_DATA_ALIGN(len); + + data = page_frag_alloc(&nc->page, len, gfp_mask); + pfmemalloc = nc->page.pfmemalloc; +@@ -780,7 +849,7 @@ static void skb_free_head(struct sk_buff *skb) + } + } + +-static void skb_release_data(struct sk_buff *skb) ++void skb_release_data(struct sk_buff *skb) + { + struct skb_shared_info *shinfo = skb_shinfo(skb); + int i; +@@ -822,7 +891,7 @@ static void skb_release_data(struct sk_buff *skb) + /* + * Free an skbuff by memory without cleaning the state. + */ +-static void kfree_skbmem(struct sk_buff *skb) ++void kfree_skbmem(struct sk_buff *skb) + { + struct sk_buff_fclones *fclones; + +@@ -1034,7 +1103,6 @@ void skb_tx_error(struct sk_buff *skb) + } + EXPORT_SYMBOL(skb_tx_error); + +-#ifdef CONFIG_TRACEPOINTS + /** + * consume_skb - free an skbuff + * @skb: buffer to free +@@ -1043,13 +1111,50 @@ EXPORT_SYMBOL(skb_tx_error); + * Functions identically to kfree_skb, but kfree_skb assumes that the frame + * is being dropped after a failure and notes that + */ ++#ifdef CONFIG_SKB_RECYCLER + void consume_skb(struct sk_buff *skb) + { + if (!skb_unref(skb)) + return; + ++ prefetch(&skb->destructor); ++ ++ /*Tian: Not sure if we need to continue using this since ++ * since unref does the work in 5.4 ++ */ ++ ++ /* ++ if (likely(atomic_read(&skb->users) == 1)) ++ smp_rmb(); ++ else if (likely(!atomic_dec_and_test(&skb->users))) ++ return; ++ */ ++ ++ /* If possible we'd like to recycle any skb rather than just free it, ++ * but in order to do that we need to release any head state too. ++ * We don't want to do this later because we'll be in a pre-emption ++ * disabled state. ++ */ ++ skb_release_head_state(skb); ++ ++ /* Can we recycle this skb? If we can then it will be much faster ++ * for us to recycle this one later than to allocate a new one ++ * from scratch. ++ */ ++ if (likely(skb->head) && likely(skb_recycler_consume(skb))) ++ return; ++ ++#ifdef CONFIG_TRACEPOINTS + trace_consume_skb(skb); +- __kfree_skb(skb); ++#endif ++ /* We're not recycling so now we need to do the rest of what we would ++ * have done in __kfree_skb (above and beyond the skb_release_head_state ++ * that we already did). ++ */ ++ if (likely(skb->head)) ++ skb_release_data(skb); ++ ++ kfree_skbmem(skb); + } + EXPORT_SYMBOL(consume_skb); + #endif +@@ -1856,6 +1961,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, + if (skb_pfmemalloc(skb)) + gfp_mask |= __GFP_MEMALLOC; + ++ size = SKB_DATA_ALIGN(size); ++ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL); + if (!data) + goto nodata; +@@ -4557,6 +4664,11 @@ static void skb_extensions_init(void) {} + + void __init skb_init(void) + { ++ skb_data_cache = kmem_cache_create_usercopy("skb_data_cache", ++ SKB_DATA_CACHE_SIZE, ++ 0, SLAB_PANIC, 0, SKB_DATA_CACHE_SIZE, ++ NULL); ++ + skbuff_head_cache = kmem_cache_create_usercopy("skbuff_head_cache", + sizeof(struct sk_buff), + 0, +@@ -4570,6 +4682,7 @@ void __init skb_init(void) + SLAB_HWCACHE_ALIGN|SLAB_PANIC, + NULL); + skb_extensions_init(); ++ skb_recycler_init(); + } + + static int +@@ -6224,6 +6337,8 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, + if (skb_pfmemalloc(skb)) + gfp_mask |= __GFP_MEMALLOC; + ++ size = SKB_DATA_ALIGN(size); ++ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL); + if (!data) + return -ENOMEM; +@@ -6340,6 +6455,8 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, + if (skb_pfmemalloc(skb)) + gfp_mask |= __GFP_MEMALLOC; + ++ size = SKB_DATA_ALIGN(size); ++ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL); + if (!data) + return -ENOMEM; diff --git a/6.1/target/linux/qualcommax/patches-6.1/9999-revert-crypto-api-disallow-identical-driver-names.patch b/6.1/target/linux/qualcommax/patches-6.1/9999-revert-crypto-api-disallow-identical-driver-names.patch new file mode 100644 index 000000000..0f4862e7f --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/9999-revert-crypto-api-disallow-identical-driver-names.patch @@ -0,0 +1,10 @@ +--- a/crypto/algapi.c ++++ b/crypto/algapi.c +@@ -290,7 +290,6 @@ static struct crypto_larval *__crypto_re + } + + if (!strcmp(q->cra_driver_name, alg->cra_name) || +- !strcmp(q->cra_driver_name, alg->cra_driver_name) || + !strcmp(q->cra_name, alg->cra_driver_name)) + goto err; + } diff --git a/6.1/target/linux/qualcommax/patches-6.1/9999-silence-UBI-NAND-warnings.patch b/6.1/target/linux/qualcommax/patches-6.1/9999-silence-UBI-NAND-warnings.patch new file mode 100644 index 000000000..2eb85cb7b --- /dev/null +++ b/6.1/target/linux/qualcommax/patches-6.1/9999-silence-UBI-NAND-warnings.patch @@ -0,0 +1,13 @@ +--- a/drivers/mtd/mtdblock.c ++++ b/drivers/mtd/mtdblock.c +@@ -261,10 +261,6 @@ static int mtdblock_open(struct mtd_blkt + return 0; + } + +- if (mtd_type_is_nand(mbd->mtd)) +- pr_warn("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n", +- mbd->tr->name, mbd->mtd->name); +- + /* OK, it's not open. Create cache info for it */ + mtdblk->count = 1; + mutex_init(&mtdblk->cache_mutex); diff --git a/6.6/target/linux/qualcommax/patches-6.6/0170-clk-qcom-ipq8074-Support-added-for-necessary-clocks-and-reset.patch b/6.6/target/linux/qualcommax/patches-6.6/0170-clk-qcom-ipq8074-Support-added-for-necessary-clocks-and-reset.patch new file mode 100644 index 000000000..76cc8caac --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0170-clk-qcom-ipq8074-Support-added-for-necessary-clocks-and-reset.patch @@ -0,0 +1,311 @@ +From 6504bc9edeb1a2a54d813f4bb5d0267e7bf827f9 Mon Sep 17 00:00:00 2001 +From: Praveenkumar I +Date: Thu, 6 Feb 2020 17:35:42 +0530 +Subject: [PATCH 4/8] clk: ipq8074: Support added for necessary clocks and + reset + +Change-Id: I21a76a44185f766e9b6dcba274392ea8e599718b +Signed-off-by: Praveenkumar I +Signed-off-by: Rajkumar Ayyasamy +--- + drivers/clk/qcom/gcc-ipq8074.c | 238 ++++++++++++++++++- + include/dt-bindings/clock/qcom,gcc-ipq8074.h | 35 ++- + 2 files changed, 258 insertions(+), 15 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq8074.c ++++ b/drivers/clk/qcom/gcc-ipq8074.c +@@ -48,6 +48,22 @@ enum { + P_UNIPHY2_TX, + }; + ++static const char * const gcc_xo_gpll4_gpll0_gpll6_gpll0_div2[] = { ++ "xo", ++ "gpll4", ++ "gpll0", ++ "gpll6", ++ "gpll0_out_main_div2", ++}; ++ ++static const struct parent_map gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map[] = { ++ { P_XO, 0 }, ++ { P_GPLL4, 1 }, ++ { P_GPLL0, 2 }, ++ { P_GPLL6, 3 }, ++ { P_GPLL0_DIV2, 4 }, ++}; ++ + static struct clk_alpha_pll gpll0_main = { + .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], +@@ -629,6 +645,12 @@ static const struct freq_tbl ftbl_pcie_a + { } + }; + ++struct freq_tbl ftbl_pcie_rchng_clk_src[] = { ++ F(19200000, P_XO, 1, 0, 0), ++ F(100000000, P_GPLL0, 8, 0, 0), ++ { } ++}; ++ + static struct clk_rcg2 pcie0_axi_clk_src = { + .cmd_rcgr = 0x75054, + .freq_tbl = ftbl_pcie_axi_clk_src, +@@ -2029,6 +2051,78 @@ static struct clk_rcg2 gp3_clk_src = { + }, + }; + ++struct freq_tbl ftbl_qdss_tsctr_clk_src[] = { ++ F(160000000, P_GPLL0_DIV2, 2.5, 0, 0), ++ F(320000000, P_GPLL0, 2.5, 0, 0), ++ F(600000000, P_GPLL6, 2, 0, 0), ++ { } ++}; ++ ++struct clk_rcg2 qdss_tsctr_clk_src = { ++ .cmd_rcgr = 0x29064, ++ .freq_tbl = ftbl_qdss_tsctr_clk_src, ++ .hid_width = 5, ++ .parent_map = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map, ++ .clkr.hw.init = &(struct clk_init_data){ ++ .name = "qdss_tsctr_clk_src", ++ .parent_names = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2, ++ .num_parents = 5, ++ .ops = &clk_rcg2_ops, ++ }, ++}; ++ ++static struct clk_fixed_factor qdss_dap_sync_clk_src = { ++ .mult = 1, ++ .div = 4, ++ .hw.init = &(struct clk_init_data){ ++ .name = "qdss_dap_sync_clk_src", ++ .parent_names = (const char *[]){ ++ "qdss_tsctr_clk_src" ++ }, ++ .num_parents = 1, ++ .ops = &clk_fixed_factor_ops, ++ }, ++}; ++ ++struct freq_tbl ftbl_qdss_at_clk_src[] = { ++ F(66670000, P_GPLL0_DIV2, 6, 0, 0), ++ F(240000000, P_GPLL6, 6, 0, 0), ++ { } ++}; ++ ++struct clk_rcg2 qdss_at_clk_src = { ++ .cmd_rcgr = 0x2900c, ++ .freq_tbl = ftbl_qdss_at_clk_src, ++ .hid_width = 5, ++ .parent_map = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2_map, ++ .clkr.hw.init = &(struct clk_init_data){ ++ .name = "qdss_at_clk_src", ++ .parent_names = gcc_xo_gpll4_gpll0_gpll6_gpll0_div2, ++ .num_parents = 5, ++ .ops = &clk_rcg2_ops, ++ }, ++}; ++ ++ ++struct freq_tbl ftbl_adss_pwm_clk_src[] = { ++ F(19200000, P_XO, 1, 0, 0), ++ F(200000000, P_GPLL0, 4, 0, 0), ++ { } ++}; ++ ++struct clk_rcg2 adss_pwm_clk_src = { ++ .cmd_rcgr = 0x1c008, ++ .freq_tbl = ftbl_adss_pwm_clk_src, ++ .hid_width = 5, ++ .parent_map = gcc_xo_gpll0_map, ++ .clkr.hw.init = &(struct clk_init_data){ ++ .name = "adss_pwm_clk_src", ++ .parent_data = gcc_xo_gpll0, ++ .num_parents = 2, ++ .ops = &clk_rcg2_ops, ++ }, ++}; ++ + static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x01008, + .clkr = { +@@ -4224,13 +4318,7 @@ static struct clk_branch gcc_gp3_clk = { + }, + }; + +-static const struct freq_tbl ftbl_pcie_rchng_clk_src[] = { +- F(19200000, P_XO, 1, 0, 0), +- F(100000000, P_GPLL0, 8, 0, 0), +- { } +-}; +- +-static struct clk_rcg2 pcie0_rchng_clk_src = { ++struct clk_rcg2 pcie0_rchng_clk_src = { + .cmd_rcgr = 0x75070, + .freq_tbl = ftbl_pcie_rchng_clk_src, + .hid_width = 5, +@@ -4322,6 +4410,114 @@ static const struct alpha_pll_config nss + .alpha_en_mask = BIT(24), + }; + ++static struct clk_branch gcc_snoc_bus_timeout2_ahb_clk = { ++ .halt_reg = 0x4700c, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x4700c, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_snoc_bus_timeout2_ahb_clk", ++ .parent_names = (const char *[]){ ++ "usb0_master_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch gcc_snoc_bus_timeout3_ahb_clk = { ++ .halt_reg = 0x47014, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x47014, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_snoc_bus_timeout3_ahb_clk", ++ .parent_names = (const char *[]){ ++ "usb1_master_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch gcc_dcc_clk = { ++ .halt_reg = 0x77004, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x77004, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_dcc_clk", ++ .parent_names = (const char *[]){ ++ "pcnoc_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch gcc_qdss_at_clk = { ++ .halt_reg = 0x29024, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x29024, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_qdss_at_clk", ++ .parent_names = (const char *[]){ ++ "qdss_at_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch gcc_qdss_dap_clk = { ++ .halt_reg = 0x29084, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x29084, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_qdss_dap_clk", ++ .parent_names = (const char *[]){ ++ "qdss_dap_sync_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch gcc_adss_pwm_clk = { ++ .halt_reg = 0x1c020, ++ .halt_bit = 31, ++ .clkr = { ++ .enable_reg = 0x1c020, ++ .enable_mask = BIT(0), ++ .hw.init = &(struct clk_init_data){ ++ .name = "gcc_adss_pwm_clk", ++ .parent_names = (const char *[]){ ++ "adss_pwm_clk_src" ++ }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ .ops = &clk_branch2_ops, ++ }, ++ }, ++}; ++ + static struct clk_hw *gcc_ipq8074_hws[] = { + &gpll0_out_main_div2.hw, + &gpll6_out_main_div2.hw, +@@ -4330,6 +4526,7 @@ static struct clk_hw *gcc_ipq8074_hws[] + &gcc_xo_div4_clk_src.hw, + &nss_noc_clk_src.hw, + &nss_ppe_cdiv_clk_src.hw, ++ &qdss_dap_sync_clk_src.hw, + }; + + static struct clk_regmap *gcc_ipq8074_clks[] = { +@@ -4561,6 +4758,15 @@ static struct clk_regmap *gcc_ipq8074_cl + [GCC_PCIE0_RCHNG_CLK] = &gcc_pcie0_rchng_clk.clkr, + [GCC_PCIE0_AXI_S_BRIDGE_CLK] = &gcc_pcie0_axi_s_bridge_clk.clkr, + [GCC_CRYPTO_PPE_CLK] = &gcc_crypto_ppe_clk.clkr, ++ [GCC_SNOC_BUS_TIMEOUT2_AHB_CLK] = &gcc_snoc_bus_timeout2_ahb_clk.clkr, ++ [GCC_SNOC_BUS_TIMEOUT3_AHB_CLK] = &gcc_snoc_bus_timeout3_ahb_clk.clkr, ++ [GCC_DCC_CLK] = &gcc_dcc_clk.clkr, ++ [QDSS_TSCTR_CLK_SRC] = &qdss_tsctr_clk_src.clkr, ++ [QDSS_AT_CLK_SRC] = &qdss_at_clk_src.clkr, ++ [GCC_QDSS_AT_CLK] = &gcc_qdss_at_clk.clkr, ++ [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr, ++ [ADSS_PWM_CLK_SRC] = &adss_pwm_clk_src.clkr, ++ [GCC_ADSS_PWM_CLK] = &gcc_adss_pwm_clk.clkr, + }; + + static const struct qcom_reset_map gcc_ipq8074_resets[] = { +--- a/include/dt-bindings/clock/qcom,gcc-ipq8074.h ++++ b/include/dt-bindings/clock/qcom,gcc-ipq8074.h +@@ -230,10 +230,19 @@ + #define GCC_GP1_CLK 221 + #define GCC_GP2_CLK 222 + #define GCC_GP3_CLK 223 +-#define GCC_PCIE0_AXI_S_BRIDGE_CLK 224 +-#define GCC_PCIE0_RCHNG_CLK_SRC 225 +-#define GCC_PCIE0_RCHNG_CLK 226 +-#define GCC_CRYPTO_PPE_CLK 227 ++#define GCC_CRYPTO_PPE_CLK 224 ++#define GCC_PCIE0_RCHNG_CLK_SRC 225 ++#define GCC_PCIE0_RCHNG_CLK 226 ++#define GCC_PCIE0_AXI_S_BRIDGE_CLK 227 ++#define GCC_SNOC_BUS_TIMEOUT2_AHB_CLK 228 ++#define GCC_SNOC_BUS_TIMEOUT3_AHB_CLK 229 ++#define GCC_DCC_CLK 230 ++#define ADSS_PWM_CLK_SRC 231 ++#define GCC_ADSS_PWM_CLK 232 ++#define QDSS_TSCTR_CLK_SRC 233 ++#define QDSS_AT_CLK_SRC 234 ++#define GCC_QDSS_AT_CLK 235 ++#define GCC_QDSS_DAP_CLK 236 + + #define GCC_BLSP1_BCR 0 + #define GCC_BLSP1_QUP1_BCR 1 diff --git a/6.6/target/linux/qualcommax/patches-6.6/0171-1-clk-qcom-ipq8074-Fix-gcc_snoc_bus_timeout_ahb_clk-offset.patch b/6.6/target/linux/qualcommax/patches-6.6/0171-1-clk-qcom-ipq8074-Fix-gcc_snoc_bus_timeout_ahb_clk-offset.patch new file mode 100644 index 000000000..b1393fc9a --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0171-1-clk-qcom-ipq8074-Fix-gcc_snoc_bus_timeout_ahb_clk-offset.patch @@ -0,0 +1,44 @@ +From 462aa0c53397ec5bf78e3e7f68aa8a3ca300f4ba Mon Sep 17 00:00:00 2001 +From: Selvam Sathappan Periakaruppan +Date: Tue, 24 Mar 2020 19:09:38 +0530 +Subject: [PATCH 5/8] clk: qcom: ipq8074: Fix gcc_snoc_bus_timeout_ahb_clk + offset + +By default, the ipq8074 V2 clks are provided in the gcc driver. +Updating the gcc_snoc_bus_timeout_ahb_clk offsets also as needed +in ipq8074 V2. + +Change-Id: I5a6e98d002f5c3354a804e55dd9ebb1f83f7f974 +Signed-off-by: Selvam Sathappan Periakaruppan +--- + drivers/clk/qcom/gcc-ipq8074.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq8074.c ++++ b/drivers/clk/qcom/gcc-ipq8074.c +@@ -4411,10 +4411,10 @@ static const struct alpha_pll_config nss + }; + + static struct clk_branch gcc_snoc_bus_timeout2_ahb_clk = { +- .halt_reg = 0x4700c, ++ .halt_reg = 0x47014, + .halt_bit = 31, + .clkr = { +- .enable_reg = 0x4700c, ++ .enable_reg = 0x47014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_snoc_bus_timeout2_ahb_clk", +@@ -4429,10 +4429,10 @@ static struct clk_branch gcc_snoc_bus_ti + }; + + static struct clk_branch gcc_snoc_bus_timeout3_ahb_clk = { +- .halt_reg = 0x47014, ++ .halt_reg = 0x4701C, + .halt_bit = 31, + .clkr = { +- .enable_reg = 0x47014, ++ .enable_reg = 0x4701C, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_snoc_bus_timeout3_ahb_clk", diff --git a/6.6/target/linux/qualcommax/patches-6.6/0171-2-clk-qcom-ipq8074-Fix-gcc_blsp1_ahb_clk-properties.patch b/6.6/target/linux/qualcommax/patches-6.6/0171-2-clk-qcom-ipq8074-Fix-gcc_blsp1_ahb_clk-properties.patch new file mode 100644 index 000000000..a7abddd5f --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0171-2-clk-qcom-ipq8074-Fix-gcc_blsp1_ahb_clk-properties.patch @@ -0,0 +1,41 @@ +From 52315bec6ed633b6a71f28b746029602f8bd70b9 Mon Sep 17 00:00:00 2001 +From: Balaji Prakash J +Date: Wed, 22 Apr 2020 20:35:30 +0530 +Subject: [PATCH] clk: ipq8074: fix gcc_blsp1_ahb_clk properties + +All the voting enabled clocks does not support the enable +from CBCR register. So, updated gcc_blsp1_ahb_clk enable +register and mask to enable bit in APCS_CLOCK_BRANCH_ENA_VOTE. + +Also, the voting controlled clocks are shared among multiple +components like APSS, RPM, NSS, TZ, etc. So, turning the +voting off from APSS does not make the clock off if it has +been voted from another component. Added the flag +BRANCH_HALT_VOTED in order to skip checking the clock +disable status. + +This change is referred from the below commits, +1. 246b4fb3af9bd65d8af794aac2f0e7b1ed9cc2dd +2. c8374157d5ae91d3b3e0d513d62808a798b32d3a + +Signed-off-by: Balaji Prakash J +Change-Id: I505cb560b31ad27a02c165fbe13bb33a2fc7d230 +--- + drivers/clk/qcom/gcc-ipq8074.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq8074.c ++++ b/drivers/clk/qcom/gcc-ipq8074.c +@@ -2125,9 +2125,10 @@ struct clk_rcg2 adss_pwm_clk_src = { + + static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x01008, ++ .halt_check = BRANCH_HALT_VOTED, + .clkr = { +- .enable_reg = 0x01008, +- .enable_mask = BIT(0), ++ .enable_reg = 0x0b004, ++ .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_ahb_clk", + .parent_hws = (const struct clk_hw *[]){ diff --git a/6.6/target/linux/qualcommax/patches-6.6/0600-1-qca-nss-ecm-support-CORE.patch b/6.6/target/linux/qualcommax/patches-6.6/0600-1-qca-nss-ecm-support-CORE.patch new file mode 100644 index 000000000..c49b95640 --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0600-1-qca-nss-ecm-support-CORE.patch @@ -0,0 +1,875 @@ +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -71,6 +71,9 @@ void brioctl_set(int (*hook)(struct net + void __user *uarg)); + int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd, + struct ifreq *ifr, void __user *uarg); ++extern void br_dev_update_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *nlstats); ++extern bool br_is_hairpin_enabled(struct net_device *dev); + + #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) + int br_multicast_list_adjacent(struct net_device *dev, +@@ -213,4 +216,42 @@ static inline clock_t br_get_ageing_time + } + #endif + ++/* QCA NSS ECM support - Start */ ++extern struct net_device *br_port_dev_get(struct net_device *dev, ++ unsigned char *addr, ++ struct sk_buff *skb, ++ unsigned int cookie); ++extern void br_refresh_fdb_entry(struct net_device *dev, const char *addr); ++extern void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid); ++extern struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev, ++ const char *addr, ++ __u16 vid); ++extern void br_fdb_update_register_notify(struct notifier_block *nb); ++extern void br_fdb_update_unregister_notify(struct notifier_block *nb); ++ ++typedef struct net_bridge_port *br_port_dev_get_hook_t(struct net_device *dev, ++ struct sk_buff *skb, ++ unsigned char *addr, ++ unsigned int cookie); ++extern br_port_dev_get_hook_t __rcu *br_port_dev_get_hook; ++ ++#define BR_FDB_EVENT_ADD 0x01 ++#define BR_FDB_EVENT_DEL 0x02 ++ ++struct br_fdb_event { ++ struct net_device *dev; ++ unsigned char addr[6]; ++ unsigned char is_local; ++ struct net_bridge *br; ++ struct net_device *orig_dev; ++}; ++extern void br_fdb_register_notify(struct notifier_block *nb); ++extern void br_fdb_unregister_notify(struct notifier_block *nb); ++ ++typedef struct net_bridge_port *br_get_dst_hook_t( ++ const struct net_bridge_port *src, ++ struct sk_buff **skb); ++extern br_get_dst_hook_t __rcu *br_get_dst_hook; ++/* QCA NSS ECM support - End */ ++ + #endif +--- a/include/linux/if_vlan.h ++++ b/include/linux/if_vlan.h +@@ -143,7 +143,10 @@ extern struct net_device *__vlan_find_de + extern int vlan_for_each(struct net_device *dev, + int (*action)(struct net_device *dev, int vid, + void *arg), void *arg); ++extern void __vlan_dev_update_accel_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *stats); /* QCA NSS ECM support */ + extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); ++extern struct net_device *vlan_dev_next_dev(const struct net_device *dev); /* QCA NSS ECM support */ + extern u16 vlan_dev_vlan_id(const struct net_device *dev); + extern __be16 vlan_dev_vlan_proto(const struct net_device *dev); + +@@ -236,6 +239,12 @@ extern void vlan_vids_del_by_dev(struct + extern bool vlan_uses_dev(const struct net_device *dev); + + #else ++static inline void __vlan_dev_update_accel_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) ++{ ++ ++} /* QCA NSS ECM support */ ++ + static inline struct net_device * + __vlan_find_dev_deep_rcu(struct net_device *real_dev, + __be16 vlan_proto, u16 vlan_id) +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -2936,6 +2936,10 @@ enum netdev_cmd { + NETDEV_OFFLOAD_XSTATS_REPORT_USED, + NETDEV_OFFLOAD_XSTATS_REPORT_DELTA, + NETDEV_XDP_FEAT_CHANGE, ++ /* QCA NSS ECM Support - Start */ ++ NETDEV_BR_JOIN, ++ NETDEV_BR_LEAVE, ++ /* QCA NSS ECM Support - End */ + }; + const char *netdev_cmd_to_name(enum netdev_cmd cmd); + +--- a/include/net/ip6_route.h ++++ b/include/net/ip6_route.h +@@ -207,6 +207,11 @@ void rt6_multipath_rebalance(struct fib6 + void rt6_uncached_list_add(struct rt6_info *rt); + void rt6_uncached_list_del(struct rt6_info *rt); + ++/* QCA NSS ECM support - Start */ ++int rt6_register_notifier(struct notifier_block *nb); ++int rt6_unregister_notifier(struct notifier_block *nb); ++/* QCA NSS ECM support - End */ ++ + static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb) + { + const struct dst_entry *dst = skb_dst(skb); +--- a/include/net/neighbour.h ++++ b/include/net/neighbour.h +@@ -249,6 +249,13 @@ static inline int neigh_parms_family(str + return p->tbl->family; + } + ++/* QCA NSS ECM support - Start */ ++struct neigh_mac_update { ++ unsigned char old_mac[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))]; ++ unsigned char update_mac[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))]; ++}; ++/* QCA NSS ECM support - End */ ++ + #define NEIGH_PRIV_ALIGN sizeof(long long) + #define NEIGH_ENTRY_SIZE(size) ALIGN((size), NEIGH_PRIV_ALIGN) + +@@ -395,6 +402,11 @@ void __neigh_for_each_release(struct nei + int (*cb)(struct neighbour *)); + int neigh_xmit(int fam, struct net_device *, const void *, struct sk_buff *); + ++/* QCA NSS ECM support - Start */ ++extern void neigh_mac_update_register_notify(struct notifier_block *nb); ++extern void neigh_mac_update_unregister_notify(struct notifier_block *nb); ++/* QCA NSS ECM support - End */ ++ + struct neigh_seq_state { + struct seq_net_private p; + struct neigh_table *tbl; +@@ -600,4 +612,5 @@ static inline void neigh_update_is_route + *notify = 1; + } + } ++ + #endif +--- a/include/net/route.h ++++ b/include/net/route.h +@@ -237,6 +237,11 @@ struct rtable *rt_dst_alloc(struct net_d + unsigned int flags, u16 type, bool noxfrm); + struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt); + ++/* QCA NSS ECM support - Start */ ++int ip_rt_register_notifier(struct notifier_block *nb); ++int ip_rt_unregister_notifier(struct notifier_block *nb); ++/* QCA NSS ECM support - End */ ++ + struct in_ifaddr; + void fib_add_ifaddr(struct in_ifaddr *); + void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *); +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -2266,4 +2266,6 @@ void br_do_suppress_nd(struct sk_buff *s + u16 vid, struct net_bridge_port *p, struct nd_msg *msg); + struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *m); + bool br_is_neigh_suppress_enabled(const struct net_bridge_port *p, u16 vid); ++#define __br_get(__hook, __default, __args ...) \ ++ (__hook ? (__hook(__args)) : (__default)) /* QCA NSS ECM support */ + #endif +--- a/net/8021q/vlan_core.c ++++ b/net/8021q/vlan_core.c +@@ -72,6 +72,28 @@ bool vlan_do_receive(struct sk_buff **sk + return true; + } + ++/* QCA NSS ECM support - Start */ ++/* Update the VLAN device with statistics from network offload engines */ ++void __vlan_dev_update_accel_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *nlstats) ++{ ++ struct vlan_pcpu_stats *stats; ++ ++ if (!is_vlan_dev(dev)) ++ return; ++ ++ stats = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, 0); ++ ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_add(&stats->rx_packets, nlstats->rx_packets); ++ u64_stats_add(&stats->rx_bytes, nlstats->rx_bytes); ++ u64_stats_add(&stats->tx_packets, nlstats->tx_packets); ++ u64_stats_add(&stats->tx_bytes, nlstats->tx_bytes); ++ u64_stats_update_end(&stats->syncp); ++} ++EXPORT_SYMBOL(__vlan_dev_update_accel_stats); ++/* QCA NSS ECM support - End */ ++ + /* Must be invoked with rcu_read_lock. */ + struct net_device *__vlan_find_dev_deep_rcu(struct net_device *dev, + __be16 vlan_proto, u16 vlan_id) +@@ -110,6 +132,15 @@ struct net_device *vlan_dev_real_dev(con + } + EXPORT_SYMBOL(vlan_dev_real_dev); + ++/* QCA NSS ECM support - Start */ ++/* Caller is responsible to hold the reference of the returned device */ ++struct net_device *vlan_dev_next_dev(const struct net_device *dev) ++{ ++ return vlan_dev_priv(dev)->real_dev; ++} ++EXPORT_SYMBOL(vlan_dev_next_dev); ++/* QCA NSS ECM support - End */ ++ + u16 vlan_dev_vlan_id(const struct net_device *dev) + { + return vlan_dev_priv(dev)->vlan_id; +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -33,6 +33,20 @@ static const struct rhashtable_params br + + static struct kmem_cache *br_fdb_cache __read_mostly; + ++ATOMIC_NOTIFIER_HEAD(br_fdb_notifier_list); ++ ++void br_fdb_register_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_register(&br_fdb_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_register_notify); ++ ++void br_fdb_unregister_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_unregister(&br_fdb_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_unregister_notify); ++ + int __init br_fdb_init(void) + { + br_fdb_cache = kmem_cache_create("bridge_fdb_cache", +@@ -195,6 +209,25 @@ static void fdb_notify(struct net_bridge + if (swdev_notify) + br_switchdev_fdb_notify(br, fdb, type); + ++ /* QCA NSS ECM support - Start */ ++ if (fdb->dst) { ++ int event; ++ struct br_fdb_event fdb_event; ++ ++ if (type == RTM_NEWNEIGH) ++ event = BR_FDB_EVENT_ADD; ++ else ++ event = BR_FDB_EVENT_DEL; ++ ++ fdb_event.dev = fdb->dst->dev; ++ ether_addr_copy(fdb_event.addr, fdb->key.addr.addr); ++ fdb_event.is_local = test_bit(BR_FDB_LOCAL, &fdb->flags); ++ atomic_notifier_call_chain(&br_fdb_notifier_list, ++ event, ++ (void *)&fdb_event); ++ } ++ /* QCA NSS ECM support - End */ ++ + skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC); + if (skb == NULL) + goto errout; +@@ -519,6 +552,22 @@ out: + spin_unlock_bh(&br->hash_lock); + } + ++/* QCA NSS ECM support - Start */ ++ATOMIC_NOTIFIER_HEAD(br_fdb_update_notifier_list); ++ ++void br_fdb_update_register_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_register(&br_fdb_update_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_update_register_notify); ++ ++void br_fdb_update_unregister_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_unregister(&br_fdb_update_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(br_fdb_update_unregister_notify); ++/* QCA NSS ECM support - End */ ++ + void br_fdb_cleanup(struct work_struct *work) + { + struct net_bridge *br = container_of(work, struct net_bridge, +@@ -527,6 +576,7 @@ void br_fdb_cleanup(struct work_struct * + unsigned long delay = hold_time(br); + unsigned long work_delay = delay; + unsigned long now = jiffies; ++ u8 mac_addr[6]; /* QCA NSS ECM support */ + + /* this part is tricky, in order to avoid blocking learning and + * consequently forwarding, we rely on rcu to delete objects with +@@ -553,8 +603,15 @@ void br_fdb_cleanup(struct work_struct * + work_delay = min(work_delay, this_timer - now); + } else { + spin_lock_bh(&br->hash_lock); +- if (!hlist_unhashed(&f->fdb_node)) ++ if (!hlist_unhashed(&f->fdb_node)) { ++ ether_addr_copy(mac_addr, f->key.addr.addr); + fdb_delete(br, f, true); ++ /* QCA NSS ECM support - Start */ ++ atomic_notifier_call_chain( ++ &br_fdb_update_notifier_list, 0, ++ (void *)mac_addr); ++ /* QCA NSS ECM support - End */ ++ } + spin_unlock_bh(&br->hash_lock); + } + } +@@ -891,6 +948,12 @@ void br_fdb_update(struct net_bridge *br + */ + if (unlikely(test_bit(BR_FDB_LOCKED, &fdb->flags))) + clear_bit(BR_FDB_LOCKED, &fdb->flags); ++ ++ /* QCA NSS ECM support - Start */ ++ atomic_notifier_call_chain( ++ &br_fdb_update_notifier_list, ++ 0, (void *)addr); ++ /* QCA NSS ECM support - End */ + } + + if (unlikely(test_bit(BR_FDB_ADDED_BY_USER, &flags))) +@@ -914,6 +977,64 @@ void br_fdb_update(struct net_bridge *br + } + } + ++/* QCA NSS ECM support - Start */ ++/* Refresh FDB entries for bridge packets being forwarded by offload engines */ ++void br_refresh_fdb_entry(struct net_device *dev, const char *addr) ++{ ++ struct net_bridge_port *p = br_port_get_rcu(dev); ++ ++ if (!p || p->state == BR_STATE_DISABLED) ++ return; ++ ++ if (!is_valid_ether_addr(addr)) { ++ pr_info("bridge: Attempt to refresh with invalid ether address %pM\n", ++ addr); ++ return; ++ } ++ ++ rcu_read_lock(); ++ br_fdb_update(p->br, p, addr, 0, true); ++ rcu_read_unlock(); ++} ++EXPORT_SYMBOL_GPL(br_refresh_fdb_entry); ++ ++/* Update timestamp of FDB entries for bridge packets being forwarded by offload engines */ ++void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid) ++{ ++ struct net_bridge_fdb_entry *fdb; ++ struct net_bridge_port *p = br_port_get_rcu(dev); ++ ++ if (!p || p->state == BR_STATE_DISABLED) ++ return; ++ ++ rcu_read_lock(); ++ fdb = fdb_find_rcu(&p->br->fdb_hash_tbl, addr, vid); ++ if (likely(fdb)) { ++ fdb->updated = jiffies; ++ } ++ rcu_read_unlock(); ++} ++EXPORT_SYMBOL_GPL(br_fdb_entry_refresh); ++ ++/* Look up the MAC address in the device's bridge fdb table */ ++struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev, ++ const char *addr, __u16 vid) ++{ ++ struct net_bridge_port *p = br_port_get_rcu(dev); ++ struct net_bridge_fdb_entry *fdb; ++ ++ if (!p || p->state == BR_STATE_DISABLED) ++ return NULL; ++ ++ rcu_read_lock(); ++ fdb = fdb_find_rcu(&p->br->fdb_hash_tbl, addr, vid); ++ rcu_read_unlock(); ++ ++ return fdb; ++} ++EXPORT_SYMBOL_GPL(br_fdb_has_entry); ++ ++/* QCA NSS ECM support - End */ + /* Dump information about entries, in response to GETNEIGH */ + int br_fdb_dump(struct sk_buff *skb, + struct netlink_callback *cb, +--- a/net/bridge/br_if.c ++++ b/net/bridge/br_if.c +@@ -26,6 +26,12 @@ + + #include "br_private.h" + ++/* QCA NSS ECM support - Start */ ++/* Hook for external forwarding logic */ ++br_port_dev_get_hook_t __rcu *br_port_dev_get_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_port_dev_get_hook); ++/* QCA NSS ECM support - End */ ++ + /* + * Determine initial path cost based on speed. + * using recommendations from 802.1d standard +@@ -697,6 +703,8 @@ int br_add_if(struct net_bridge *br, str + + kobject_uevent(&p->kobj, KOBJ_ADD); + ++ call_netdevice_notifiers(NETDEV_BR_JOIN, dev); /* QCA NSS ECM support */ ++ + return 0; + + err6: +@@ -732,6 +740,8 @@ int br_del_if(struct net_bridge *br, str + if (!p || p->br != br) + return -EINVAL; + ++ call_netdevice_notifiers(NETDEV_BR_LEAVE, dev); /* QCA NSS ECM support */ ++ + /* Since more than one interface can be attached to a bridge, + * there still maybe an alternate path for netconsole to use; + * therefore there is no reason for a NETDEV_RELEASE event. +@@ -775,3 +785,97 @@ bool br_port_flag_is_set(const struct ne + return p->flags & flag; + } + EXPORT_SYMBOL_GPL(br_port_flag_is_set); ++ ++/* br_port_dev_get() ++ * If a skb is provided, and the br_port_dev_get_hook_t hook exists, ++ * use that to try and determine the egress port for that skb. ++ * If not, or no egress port could be determined, use the given addr ++ * to identify the port to which it is reachable, ++ * returing a reference to the net device associated with that port. ++ * ++ * NOTE: Return NULL if given dev is not a bridge or the mac has no ++ * associated port. ++ */ ++struct net_device *br_port_dev_get(struct net_device *dev, unsigned char *addr, ++ struct sk_buff *skb, ++ unsigned int cookie) ++{ ++ struct net_bridge_fdb_entry *fdbe; ++ struct net_bridge *br; ++ struct net_device *netdev = NULL; ++ ++ /* Is this a bridge? */ ++ if (!(dev->priv_flags & IFF_EBRIDGE)) ++ return NULL; ++ ++ rcu_read_lock(); ++ ++ /* If the hook exists and the skb isn't NULL, try and get the port */ ++ if (skb) { ++ br_port_dev_get_hook_t *port_dev_get_hook; ++ ++ port_dev_get_hook = rcu_dereference(br_port_dev_get_hook); ++ if (port_dev_get_hook) { ++ struct net_bridge_port *pdst = ++ __br_get(port_dev_get_hook, NULL, dev, skb, ++ addr, cookie); ++ if (pdst) { ++ dev_hold(pdst->dev); ++ netdev = pdst->dev; ++ goto out; ++ } ++ } ++ } ++ ++ /* Either there is no hook, or can't ++ * determine the port to use - fall back to using FDB ++ */ ++ ++ br = netdev_priv(dev); ++ ++ /* Lookup the fdb entry and get reference to the port dev */ ++ fdbe = br_fdb_find_rcu(br, addr, 0); ++ if (fdbe && fdbe->dst) { ++ netdev = fdbe->dst->dev; /* port device */ ++ dev_hold(netdev); ++ } ++out: ++ rcu_read_unlock(); ++ return netdev; ++} ++EXPORT_SYMBOL_GPL(br_port_dev_get); ++ ++/* Update bridge statistics for bridge packets processed by offload engines */ ++void br_dev_update_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *nlstats) ++{ ++ struct pcpu_sw_netstats *tstats; ++ ++ /* Is this a bridge? */ ++ if (!(dev->priv_flags & IFF_EBRIDGE)) ++ return; ++ ++ tstats = this_cpu_ptr(dev->tstats); ++ ++ u64_stats_update_begin(&tstats->syncp); ++ u64_stats_add(&tstats->rx_packets, nlstats->rx_packets); ++ u64_stats_add(&tstats->rx_bytes, nlstats->rx_bytes); ++ u64_stats_add(&tstats->tx_packets, nlstats->tx_packets); ++ u64_stats_add(&tstats->tx_bytes, nlstats->tx_bytes); ++ u64_stats_update_end(&tstats->syncp); ++} ++EXPORT_SYMBOL_GPL(br_dev_update_stats); ++ ++/* QCA NSS ECM support - Start */ ++/* API to know if hairpin feature is enabled/disabled on this bridge port */ ++bool br_is_hairpin_enabled(struct net_device *dev) ++{ ++ struct net_bridge_port *port = br_port_get_check_rcu(dev); ++ ++ if (likely(port)) ++ return port->flags & BR_HAIRPIN_MODE; ++ return false; ++} ++EXPORT_SYMBOL_GPL(br_is_hairpin_enabled); ++ ++/* QCA NSS ECM support - End */ +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -1275,6 +1275,22 @@ static void neigh_update_hhs(struct neig + } + } + ++/* QCA NSS ECM support - Start */ ++ATOMIC_NOTIFIER_HEAD(neigh_mac_update_notifier_list); ++ ++void neigh_mac_update_register_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_register(&neigh_mac_update_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(neigh_mac_update_register_notify); ++ ++void neigh_mac_update_unregister_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_unregister(&neigh_mac_update_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(neigh_mac_update_unregister_notify); ++/* QCA NSS ECM support - End */ ++ + /* Generic update routine. + -- lladdr is new lladdr or NULL, if it is not supplied. + -- new is new state. +@@ -1303,6 +1319,7 @@ static int __neigh_update(struct neighbo + struct net_device *dev; + int err, notify = 0; + u8 old; ++ struct neigh_mac_update nmu; /* QCA NSS ECM support */ + + trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid); + +@@ -1317,7 +1334,10 @@ static int __neigh_update(struct neighbo + new = old; + goto out; + } +- if (!(flags & NEIGH_UPDATE_F_ADMIN) && ++ ++ memset(&nmu, 0, sizeof(struct neigh_mac_update)); /* QCA NSS ECM support */ ++ ++ if (!(flags & NEIGH_UPDATE_F_ADMIN) && + (old & (NUD_NOARP | NUD_PERMANENT))) + goto out; + +@@ -1354,7 +1374,12 @@ static int __neigh_update(struct neighbo + - compare new & old + - if they are different, check override flag + */ +- if ((old & NUD_VALID) && ++ /* QCA NSS ECM update - Start */ ++ memcpy(nmu.old_mac, neigh->ha, dev->addr_len); ++ memcpy(nmu.update_mac, lladdr, dev->addr_len); ++ /* QCA NSS ECM update - End */ ++ ++ if ((old & NUD_VALID) && + !memcmp(lladdr, neigh->ha, dev->addr_len)) + lladdr = neigh->ha; + } else { +@@ -1476,8 +1501,11 @@ out: + neigh_update_gc_list(neigh); + if (managed_update) + neigh_update_managed_list(neigh); +- if (notify) ++ if (notify) { + neigh_update_notify(neigh, nlmsg_pid); ++ atomic_notifier_call_chain(&neigh_mac_update_notifier_list, 0, ++ (struct neigh_mac_update *)&nmu); /* QCA NSS ECM support */ ++ } + trace_neigh_update_done(neigh, err); + return err; + } +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -1211,6 +1211,9 @@ static bool fib_valid_key_len(u32 key, u + static void fib_remove_alias(struct trie *t, struct key_vector *tp, + struct key_vector *l, struct fib_alias *old); + ++/* Define route change notification chain. */ ++static BLOCKING_NOTIFIER_HEAD(iproute_chain); /* QCA NSS ECM support */ ++ + /* Caller must hold RTNL. */ + int fib_table_insert(struct net *net, struct fib_table *tb, + struct fib_config *cfg, struct netlink_ext_ack *extack) +@@ -1404,6 +1407,9 @@ int fib_table_insert(struct net *net, st + rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, new_fa->tb_id, + &cfg->fc_nlinfo, nlflags); + succeeded: ++ blocking_notifier_call_chain(&iproute_chain, ++ RTM_NEWROUTE, fi); ++ + return 0; + + out_remove_new_fa: +@@ -1775,6 +1781,9 @@ int fib_table_delete(struct net *net, st + if (fa_to_delete->fa_state & FA_S_ACCESSED) + rt_cache_flush(cfg->fc_nlinfo.nl_net); + ++ blocking_notifier_call_chain(&iproute_chain, ++ RTM_DELROUTE, fa_to_delete->fa_info); ++ + fib_release_info(fa_to_delete->fa_info); + alias_free_mem_rcu(fa_to_delete); + return 0; +@@ -2407,6 +2416,20 @@ void __init fib_trie_init(void) + 0, SLAB_PANIC | SLAB_ACCOUNT, NULL); + } + ++/* QCA NSS ECM support - Start */ ++int ip_rt_register_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register(&iproute_chain, nb); ++} ++EXPORT_SYMBOL(ip_rt_register_notifier); ++ ++int ip_rt_unregister_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_unregister(&iproute_chain, nb); ++} ++EXPORT_SYMBOL(ip_rt_unregister_notifier); ++/* QCA NSS ECM support - End */ ++ + struct fib_table *fib_trie_table(u32 id, struct fib_table *alias) + { + struct fib_table *tb; +--- a/net/ipv6/ndisc.c ++++ b/net/ipv6/ndisc.c +@@ -666,6 +666,7 @@ void ndisc_send_ns(struct net_device *de + if (skb) + ndisc_send_skb(skb, daddr, saddr); + } ++EXPORT_SYMBOL(ndisc_send_ns); + + void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, + const struct in6_addr *daddr) +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -197,6 +197,9 @@ static void rt6_uncached_list_flush_dev( + } + } + ++/* Define route change notification chain. */ ++ATOMIC_NOTIFIER_HEAD(ip6route_chain); /* QCA NSS ECM support */ ++ + static inline const void *choose_neigh_daddr(const struct in6_addr *p, + struct sk_buff *skb, + const void *daddr) +@@ -3864,6 +3867,10 @@ int ip6_route_add(struct fib6_config *cf + return PTR_ERR(rt); + + err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack); ++ if (!err) ++ atomic_notifier_call_chain(&ip6route_chain, ++ RTM_NEWROUTE, rt); ++ + fib6_info_release(rt); + + return err; +@@ -3885,6 +3892,9 @@ static int __ip6_del_rt(struct fib6_info + err = fib6_del(rt, info); + spin_unlock_bh(&table->tb6_lock); + ++ if (!err) ++ atomic_notifier_call_chain(&ip6route_chain, ++ RTM_DELROUTE, rt); + out: + fib6_info_release(rt); + return err; +@@ -6329,6 +6339,20 @@ static int ip6_route_dev_notify(struct n + return NOTIFY_OK; + } + ++/* QCA NSS ECM support - Start */ ++int rt6_register_notifier(struct notifier_block *nb) ++{ ++ return atomic_notifier_chain_register(&ip6route_chain, nb); ++} ++EXPORT_SYMBOL(rt6_register_notifier); ++ ++int rt6_unregister_notifier(struct notifier_block *nb) ++{ ++ return atomic_notifier_chain_unregister(&ip6route_chain, nb); ++} ++EXPORT_SYMBOL(rt6_unregister_notifier); ++/* QCA NSS ECM support - End */ ++ + /* + * /proc + */ +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -1673,6 +1673,7 @@ const char *netdev_cmd_to_name(enum netd + N(PRE_CHANGEADDR) N(OFFLOAD_XSTATS_ENABLE) N(OFFLOAD_XSTATS_DISABLE) + N(OFFLOAD_XSTATS_REPORT_USED) N(OFFLOAD_XSTATS_REPORT_DELTA) + N(XDP_FEAT_CHANGE) ++ N(BR_JOIN) N(BR_LEAVE) + } + #undef N + return "UNKNOWN_NETDEV_EVENT"; +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -1002,6 +1002,7 @@ void inet6_ifa_finish_destroy(struct ine + + kfree_rcu(ifp, rcu); + } ++EXPORT_SYMBOL(inet6_ifa_finish_destroy); + + static void + ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) +--- a/include/net/vxlan.h ++++ b/include/net/vxlan.h +@@ -440,6 +440,15 @@ static inline __be32 vxlan_compute_rco(u + return vni_field; + } + ++/* ++ * vxlan_get_vni() ++ * Returns the vni corresponding to tunnel ++ */ ++static inline u32 vxlan_get_vni(struct vxlan_dev *vxlan_tun) ++{ ++ return be32_to_cpu(vxlan_tun->cfg.vni); ++} ++ + static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs) + { + return vs->sock->sk->sk_family; +--- a/include/uapi/linux/in.h ++++ b/include/uapi/linux/in.h +@@ -63,6 +63,8 @@ enum { + #define IPPROTO_MTP IPPROTO_MTP + IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */ + #define IPPROTO_BEETPH IPPROTO_BEETPH ++ IPPROTO_ETHERIP = 97, /* ETHERIP protocol number */ ++#define IPPROTO_ETHERIP IPPROTO_ETHERIP + IPPROTO_ENCAP = 98, /* Encapsulation Header */ + #define IPPROTO_ENCAP IPPROTO_ENCAP + IPPROTO_PIM = 103, /* Protocol Independent Multicast */ +@@ -327,7 +329,7 @@ struct sockaddr_in { + #endif + + /* contains the htonl type stuff.. */ +-#include ++#include + + + #endif /* _UAPI_LINUX_IN_H */ +--- a/tools/include/uapi/linux/in.h ++++ b/tools/include/uapi/linux/in.h +@@ -63,6 +63,8 @@ enum { + #define IPPROTO_MTP IPPROTO_MTP + IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */ + #define IPPROTO_BEETPH IPPROTO_BEETPH ++ IPPROTO_ETHERIP = 97, /* ETHERIP protocol number */ ++#define IPPROTO_ETHERIP IPPROTO_ETHERIP + IPPROTO_ENCAP = 98, /* Encapsulation Header */ + #define IPPROTO_ENCAP IPPROTO_ENCAP + IPPROTO_PIM = 103, /* Protocol Independent Multicast */ +@@ -327,7 +329,7 @@ struct sockaddr_in { + #endif + + /* contains the htonl type stuff.. */ +-#include ++#include + + + #endif /* _UAPI_LINUX_IN_H */ +--- a/net/netfilter/nf_conntrack_ecache.c ++++ b/net/netfilter/nf_conntrack_ecache.c +@@ -266,7 +266,6 @@ void nf_conntrack_register_notifier(stru + mutex_lock(&nf_ct_ecache_mutex); + notify = rcu_dereference_protected(net->ct.nf_conntrack_event_cb, + lockdep_is_held(&nf_ct_ecache_mutex)); +- WARN_ON_ONCE(notify); + rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new); + mutex_unlock(&nf_ct_ecache_mutex); + } +--- a/include/net/netns/conntrack.h ++++ b/include/net/netns/conntrack.h +@@ -26,6 +26,7 @@ struct nf_tcp_net { + unsigned int timeouts[TCP_CONNTRACK_TIMEOUT_MAX]; + u8 tcp_loose; + u8 tcp_be_liberal; ++ u8 tcp_no_window_check; + u8 tcp_max_retrans; + u8 tcp_ignore_invalid_rst; + #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) +--- a/net/netfilter/nf_conntrack_proto_tcp.c ++++ b/net/netfilter/nf_conntrack_proto_tcp.c +@@ -515,11 +515,15 @@ tcp_in_window(struct nf_conn *ct, enum i + struct ip_ct_tcp *state = &ct->proto.tcp; + struct ip_ct_tcp_state *sender = &state->seen[dir]; + struct ip_ct_tcp_state *receiver = &state->seen[!dir]; ++ const struct nf_tcp_net *tn = nf_tcp_pernet(nf_ct_net(ct)); + __u32 seq, ack, sack, end, win, swin; + bool in_recv_win, seq_ok; + s32 receiver_offset; + u16 win_raw; + ++ if (tn->tcp_no_window_check) ++ return NFCT_TCP_ACCEPT; ++ + /* + * Get the required data from the packet. + */ +@@ -1285,7 +1289,7 @@ int nf_conntrack_tcp_packet(struct nf_co + IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && + timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK]) + timeout = timeouts[TCP_CONNTRACK_UNACK]; +- else if (ct->proto.tcp.last_win == 0 && ++ else if (!tn->tcp_no_window_check && ct->proto.tcp.last_win == 0 && + timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS]) + timeout = timeouts[TCP_CONNTRACK_RETRANS]; + else +@@ -1601,6 +1605,9 @@ void nf_conntrack_tcp_init_net(struct ne + */ + tn->tcp_be_liberal = 0; + ++ /* Skip Windows Check */ ++ tn->tcp_no_window_check = 0; ++ + /* If it's non-zero, we turn off RST sequence number check */ + tn->tcp_ignore_invalid_rst = 0; + +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -633,6 +633,7 @@ enum nf_ct_sysctl_index { + #endif + NF_SYSCTL_CT_PROTO_TCP_LOOSE, + NF_SYSCTL_CT_PROTO_TCP_LIBERAL, ++ NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK, + NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST, + NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS, + NF_SYSCTL_CT_PROTO_TIMEOUT_UDP, +@@ -840,6 +841,14 @@ static struct ctl_table nf_ct_sysctl_tab + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, ++ [NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK] = { ++ .procname = "nf_conntrack_tcp_no_window_check", ++ .maxlen = sizeof(u8), ++ .mode = 0644, ++ .proc_handler = proc_dou8vec_minmax, ++ .extra1 = SYSCTL_ZERO, ++ .extra2 = SYSCTL_ONE, ++ }, + [NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST] = { + .procname = "nf_conntrack_tcp_ignore_invalid_rst", + .maxlen = sizeof(u8), +@@ -1050,6 +1059,7 @@ static void nf_conntrack_standalone_init + + XASSIGN(LOOSE, &tn->tcp_loose); + XASSIGN(LIBERAL, &tn->tcp_be_liberal); ++ XASSIGN(NO_WINDOW_CHECK, &tn->tcp_no_window_check); + XASSIGN(MAX_RETRANS, &tn->tcp_max_retrans); + XASSIGN(IGNORE_INVALID_RST, &tn->tcp_ignore_invalid_rst); + #undef XASSIGN diff --git a/6.6/target/linux/qualcommax/patches-6.6/0600-2-qca-nss-ecm-support-PPPOE-offload.patch b/6.6/target/linux/qualcommax/patches-6.6/0600-2-qca-nss-ecm-support-PPPOE-offload.patch new file mode 100644 index 000000000..e59290878 --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0600-2-qca-nss-ecm-support-PPPOE-offload.patch @@ -0,0 +1,600 @@ +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -48,6 +48,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -254,6 +255,25 @@ struct ppp_net { + #define seq_before(a, b) ((s32)((a) - (b)) < 0) + #define seq_after(a, b) ((s32)((a) - (b)) > 0) + ++ ++/* ++ * Registration/Unregistration methods ++ * for PPP channel connect and disconnect event notifications. ++ */ ++RAW_NOTIFIER_HEAD(ppp_channel_connection_notifier_list); ++ ++void ppp_channel_connection_register_notify(struct notifier_block *nb) ++{ ++ raw_notifier_chain_register(&ppp_channel_connection_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(ppp_channel_connection_register_notify); ++ ++void ppp_channel_connection_unregister_notify(struct notifier_block *nb) ++{ ++ raw_notifier_chain_unregister(&ppp_channel_connection_notifier_list, nb); ++} ++EXPORT_SYMBOL_GPL(ppp_channel_connection_unregister_notify); ++ + /* Prototypes. */ + static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct file *file, unsigned int cmd, unsigned long arg); +@@ -3453,7 +3473,10 @@ ppp_connect_channel(struct channel *pch, + struct ppp_net *pn; + int ret = -ENXIO; + int hdrlen; ++ int ppp_proto; ++ int version; + ++ int notify = 0; + pn = ppp_pernet(pch->chan_net); + + mutex_lock(&pn->all_ppp_mutex); +@@ -3485,13 +3508,40 @@ ppp_connect_channel(struct channel *pch, + ++ppp->n_channels; + pch->ppp = ppp; + refcount_inc(&ppp->file.refcnt); ++ ++ /* Set the netdev priv flag if the prototype ++ * is L2TP or PPTP. Return success in all cases ++ */ ++ if (!pch->chan) ++ goto out2; ++ ++ ppp_proto = ppp_channel_get_protocol(pch->chan); ++ if (ppp_proto == PX_PROTO_PPTP) { ++ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_PPTP; ++ } else if (ppp_proto == PX_PROTO_OL2TP) { ++ version = ppp_channel_get_proto_version(pch->chan); ++ if (version == 2) ++ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_L2TPV2; ++ else if (version == 3) ++ ppp->dev->priv_flags_ext |= IFF_EXT_PPP_L2TPV3; ++ } ++ notify = 1; ++ ++ out2: + ppp_unlock(ppp); + ret = 0; +- + outl: + write_unlock_bh(&pch->upl); + out: + mutex_unlock(&pn->all_ppp_mutex); ++ ++ if (notify && ppp && ppp->dev) { ++ dev_hold(ppp->dev); ++ raw_notifier_call_chain(&ppp_channel_connection_notifier_list, ++ PPP_CHANNEL_CONNECT, ppp->dev); ++ dev_put(ppp->dev); ++ } ++ + return ret; + } + +@@ -3509,6 +3559,13 @@ ppp_disconnect_channel(struct channel *p + pch->ppp = NULL; + write_unlock_bh(&pch->upl); + if (ppp) { ++ if (ppp->dev) { ++ dev_hold(ppp->dev); ++ raw_notifier_call_chain(&ppp_channel_connection_notifier_list, ++ PPP_CHANNEL_DISCONNECT, ppp->dev); ++ dev_put(ppp->dev); ++ } ++ + /* remove it from the ppp unit's list */ + ppp_lock(ppp); + list_del(&pch->clist); +@@ -3588,6 +3645,222 @@ static void *unit_find(struct idr *p, in + return idr_find(p, n); + } + ++/* Updates the PPP interface statistics. */ ++void ppp_update_stats(struct net_device *dev, unsigned long rx_packets, ++ unsigned long rx_bytes, unsigned long tx_packets, ++ unsigned long tx_bytes, unsigned long rx_errors, ++ unsigned long tx_errors, unsigned long rx_dropped, ++ unsigned long tx_dropped) ++{ ++ struct ppp *ppp; ++ ++ if (!dev) ++ return; ++ ++ if (dev->type != ARPHRD_PPP) ++ return; ++ ++ ppp = netdev_priv(dev); ++ ++ ppp_xmit_lock(ppp); ++ ppp->stats64.tx_packets += tx_packets; ++ ppp->stats64.tx_bytes += tx_bytes; ++ ppp->dev->stats.tx_errors += tx_errors; ++ ppp->dev->stats.tx_dropped += tx_dropped; ++ if (tx_packets) ++ ppp->last_xmit = jiffies; ++ ppp_xmit_unlock(ppp); ++ ++ ppp_recv_lock(ppp); ++ ppp->stats64.rx_packets += rx_packets; ++ ppp->stats64.rx_bytes += rx_bytes; ++ ppp->dev->stats.rx_errors += rx_errors; ++ ppp->dev->stats.rx_dropped += rx_dropped; ++ if (rx_packets) ++ ppp->last_recv = jiffies; ++ ppp_recv_unlock(ppp); ++} ++ ++/* Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 if ++ * the device is not PPP. ++ */ ++int ppp_is_multilink(struct net_device *dev) ++{ ++ struct ppp *ppp; ++ unsigned int flags; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ ppp_lock(ppp); ++ flags = ppp->flags; ++ ppp_unlock(ppp); ++ ++ if (flags & SC_MULTILINK) ++ return 1; ++ ++ return 0; ++} ++EXPORT_SYMBOL(ppp_is_multilink); ++ ++/* ppp_channel_get_protocol() ++ * Call this to obtain the underlying protocol of the PPP channel, ++ * e.g. PX_PROTO_OE ++ * ++ * NOTE: Some channels do not use PX sockets so the protocol value may be very ++ * different for them. ++ * NOTE: -1 indicates failure. ++ * NOTE: Once you know the channel protocol you may then either cast 'chan' to ++ * its sub-class or use the channel protocol specific API's as provided by that ++ * channel sub type. ++ */ ++int ppp_channel_get_protocol(struct ppp_channel *chan) ++{ ++ if (!chan->ops->get_channel_protocol) ++ return -1; ++ ++ return chan->ops->get_channel_protocol(chan); ++} ++EXPORT_SYMBOL(ppp_channel_get_protocol); ++ ++/* ppp_channel_get_proto_version() ++ * Call this to get channel protocol version ++ */ ++int ppp_channel_get_proto_version(struct ppp_channel *chan) ++{ ++ if (!chan->ops->get_channel_protocol_ver) ++ return -1; ++ ++ return chan->ops->get_channel_protocol_ver(chan); ++} ++EXPORT_SYMBOL(ppp_channel_get_proto_version); ++ ++/* ppp_channel_hold() ++ * Call this to hold a channel. ++ * ++ * Returns true on success or false if the hold could not happen. ++ * ++ * NOTE: chan must be protected against destruction during this call - ++ * either by correct locking etc. or because you already have an implicit ++ * or explicit hold to the channel already and this is an additional hold. ++ */ ++bool ppp_channel_hold(struct ppp_channel *chan) ++{ ++ if (!chan->ops->hold) ++ return false; ++ ++ chan->ops->hold(chan); ++ return true; ++} ++EXPORT_SYMBOL(ppp_channel_hold); ++ ++/* ppp_channel_release() ++ * Call this to release a hold you have upon a channel ++ */ ++void ppp_channel_release(struct ppp_channel *chan) ++{ ++ chan->ops->release(chan); ++} ++EXPORT_SYMBOL(ppp_channel_release); ++ ++/* Check if ppp xmit lock is on hold */ ++bool ppp_is_xmit_locked(struct net_device *dev) ++{ ++ struct ppp *ppp; ++ ++ if (!dev) ++ return false; ++ ++ if (dev->type != ARPHRD_PPP) ++ return false; ++ ++ ppp = netdev_priv(dev); ++ if (!ppp) ++ return false; ++ ++ if (spin_is_locked(&(ppp)->wlock)) ++ return true; ++ ++ return false; ++} ++EXPORT_SYMBOL(ppp_is_xmit_locked); ++ ++/* ppp_hold_channels() ++ * Returns the PPP channels of the PPP device, storing each one into ++ * channels[]. ++ * ++ * channels[] has chan_sz elements. ++ * This function returns the number of channels stored, up to chan_sz. ++ * It will return < 0 if the device is not PPP. ++ * ++ * You MUST release the channels using ppp_release_channels(). ++ */ ++int ppp_hold_channels(struct net_device *dev, struct ppp_channel *channels[], ++ unsigned int chan_sz) ++{ ++ struct ppp *ppp; ++ int c; ++ struct channel *pch; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ ++ c = 0; ++ ppp_lock(ppp); ++ list_for_each_entry(pch, &ppp->channels, clist) { ++ struct ppp_channel *chan; ++ ++ if (!pch->chan) { ++ /* Channel is going / gone away */ ++ continue; ++ } ++ ++ if (c == chan_sz) { ++ /* No space to record channel */ ++ ppp_unlock(ppp); ++ return c; ++ } ++ ++ /* Hold the channel, if supported */ ++ chan = pch->chan; ++ if (!chan->ops->hold) ++ continue; ++ ++ chan->ops->hold(chan); ++ ++ /* Record the channel */ ++ channels[c++] = chan; ++ } ++ ppp_unlock(ppp); ++ return c; ++} ++EXPORT_SYMBOL(ppp_hold_channels); ++ ++/* ppp_release_channels() ++ * Releases channels ++ */ ++void ppp_release_channels(struct ppp_channel *channels[], unsigned int chan_sz) ++{ ++ unsigned int c; ++ ++ for (c = 0; c < chan_sz; ++c) { ++ struct ppp_channel *chan; ++ ++ chan = channels[c]; ++ chan->ops->release(chan); ++ } ++} ++EXPORT_SYMBOL(ppp_release_channels); ++ + /* Module/initialization stuff */ + + module_init(ppp_init); +@@ -3604,6 +3877,7 @@ EXPORT_SYMBOL(ppp_input_error); + EXPORT_SYMBOL(ppp_output_wakeup); + EXPORT_SYMBOL(ppp_register_compressor); + EXPORT_SYMBOL(ppp_unregister_compressor); ++EXPORT_SYMBOL(ppp_update_stats); + MODULE_LICENSE("GPL"); + MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0); + MODULE_ALIAS_RTNL_LINK("ppp"); +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -62,6 +62,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -87,7 +88,7 @@ + static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb); + + static const struct proto_ops pppoe_ops; +-static const struct ppp_channel_ops pppoe_chan_ops; ++static const struct pppoe_channel_ops pppoe_chan_ops; + + /* per-net private data for this module */ + static unsigned int pppoe_net_id __read_mostly; +@@ -692,7 +693,7 @@ static int pppoe_connect(struct socket * + + po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2; + po->chan.private = sk; +- po->chan.ops = &pppoe_chan_ops; ++ po->chan.ops = (struct ppp_channel_ops *)&pppoe_chan_ops; + + error = ppp_register_net_channel(dev_net(dev), &po->chan); + if (error) { +@@ -995,9 +996,80 @@ static int pppoe_fill_forward_path(struc + return 0; + } + +-static const struct ppp_channel_ops pppoe_chan_ops = { +- .start_xmit = pppoe_xmit, +- .fill_forward_path = pppoe_fill_forward_path, ++/************************************************************************ ++ * ++ * function called by generic PPP driver to hold channel ++ * ++ ***********************************************************************/ ++static void pppoe_hold_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_hold(sk); ++} ++ ++/************************************************************************ ++ * ++ * function called by generic PPP driver to release channel ++ * ++ ***********************************************************************/ ++static void pppoe_release_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_put(sk); ++} ++ ++/************************************************************************ ++ * ++ * function called to get the channel protocol type ++ * ++ ***********************************************************************/ ++static int pppoe_get_channel_protocol(struct ppp_channel *chan) ++{ ++ return PX_PROTO_OE; ++} ++ ++/************************************************************************ ++ * ++ * function called to get the PPPoE channel addressing ++ * NOTE: This function returns a HOLD to the netdevice ++ * ++ ***********************************************************************/ ++static int pppoe_get_addressing(struct ppp_channel *chan, ++ struct pppoe_opt *addressing) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ struct pppox_sock *po = pppox_sk(sk); ++ int err = 0; ++ ++ *addressing = po->proto.pppoe; ++ if (!addressing->dev) ++ return -ENODEV; ++ ++ dev_hold(addressing->dev); ++ return err; ++} ++ ++/* pppoe_channel_addressing_get() ++ * Return PPPoE channel specific addressing information. ++ */ ++int pppoe_channel_addressing_get(struct ppp_channel *chan, ++ struct pppoe_opt *addressing) ++{ ++ return pppoe_get_addressing(chan, addressing); ++} ++EXPORT_SYMBOL(pppoe_channel_addressing_get); ++ ++static const struct pppoe_channel_ops pppoe_chan_ops = { ++ /* PPPoE specific channel ops */ ++ .get_addressing = pppoe_get_addressing, ++ /* General ppp channel ops */ ++ .ops.start_xmit = pppoe_xmit, ++ .ops.get_channel_protocol = pppoe_get_channel_protocol, ++ .ops.hold = pppoe_hold_chan, ++ .ops.release = pppoe_release_chan, ++ .ops.fill_forward_path = pppoe_fill_forward_path, + }; + + static int pppoe_recvmsg(struct socket *sock, struct msghdr *m, +--- a/include/linux/if_pppox.h ++++ b/include/linux/if_pppox.h +@@ -91,4 +91,17 @@ enum { + PPPOX_DEAD = 16 /* dead, useless, please clean me up!*/ + }; + ++/* ++ * PPPoE Channel specific operations ++ */ ++struct pppoe_channel_ops { ++ /* Must be first - general to all PPP channels */ ++ struct ppp_channel_ops ops; ++ int (*get_addressing)(struct ppp_channel *, struct pppoe_opt *); ++}; ++ ++/* Return PPPoE channel specific addressing information */ ++extern int pppoe_channel_addressing_get(struct ppp_channel *chan, ++ struct pppoe_opt *addressing); ++ + #endif /* !(__LINUX_IF_PPPOX_H) */ +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1762,6 +1762,36 @@ enum netdev_priv_flags { + IFF_NO_IP_ALIGN = BIT_ULL(34), + }; + ++/** ++ * enum netdev_priv_flags_ext - &struct net_device priv_flags_ext ++ * ++ * These flags are used to check for device type and can be ++ * set and used by the drivers ++ * ++ * @IFF_EXT_TUN_TAP: device is a TUN/TAP device ++ * @IFF_EXT_PPP_L2TPV2: device is a L2TPV2 device ++ * @IFF_EXT_PPP_L2TPV3: device is a L2TPV3 device ++ * @IFF_EXT_PPP_PPTP: device is a PPTP device ++ * @IFF_EXT_GRE_V4_TAP: device is a GRE IPv4 TAP device ++ * @IFF_EXT_GRE_V6_TAP: device is a GRE IPv6 TAP device ++ * @IFF_EXT_IFB: device is an IFB device ++ * @IFF_EXT_MAPT: device is an MAPT device ++ * @IFF_EXT_HW_NO_OFFLOAD: device is an NON Offload device ++ * @IFF_EXT_L2TPV3: device is a L2TPV3 Ethernet device ++ */ ++enum netdev_priv_flags_ext { ++ IFF_EXT_TUN_TAP = 1<<0, ++ IFF_EXT_PPP_L2TPV2 = 1<<1, ++ IFF_EXT_PPP_L2TPV3 = 1<<2, ++ IFF_EXT_PPP_PPTP = 1<<3, ++ IFF_EXT_GRE_V4_TAP = 1<<4, ++ IFF_EXT_GRE_V6_TAP = 1<<5, ++ IFF_EXT_IFB = 1<<6, ++ IFF_EXT_MAPT = 1<<7, ++ IFF_EXT_HW_NO_OFFLOAD = 1<<8, ++ IFF_EXT_ETH_L2TPV3 = 1<<9, ++}; ++ + #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN + #define IFF_EBRIDGE IFF_EBRIDGE + #define IFF_BONDING IFF_BONDING +@@ -2127,6 +2157,7 @@ struct net_device { + unsigned int flags; + xdp_features_t xdp_features; + unsigned long long priv_flags; ++ unsigned int priv_flags_ext; + const struct net_device_ops *netdev_ops; + const struct xdp_metadata_ops *xdp_metadata_ops; + int ifindex; +--- a/include/linux/ppp_channel.h ++++ b/include/linux/ppp_channel.h +@@ -19,6 +19,10 @@ + #include + #include + #include ++#include ++ ++#define PPP_CHANNEL_DISCONNECT 0 ++#define PPP_CHANNEL_CONNECT 1 + + struct net_device_path; + struct net_device_path_ctx; +@@ -30,9 +34,19 @@ struct ppp_channel_ops { + int (*start_xmit)(struct ppp_channel *, struct sk_buff *); + /* Handle an ioctl call that has come in via /dev/ppp. */ + int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long); ++ /* Get channel protocol type, one of PX_PROTO_XYZ or specific to ++ * the channel subtype ++ */ ++ int (*get_channel_protocol)(struct ppp_channel *); ++ /* Get channel protocol version */ ++ int (*get_channel_protocol_ver)(struct ppp_channel *); ++ /* Hold the channel from being destroyed */ ++ void (*hold)(struct ppp_channel *); ++ /* Release hold on the channel */ ++ void (*release)(struct ppp_channel *); + int (*fill_forward_path)(struct net_device_path_ctx *, +- struct net_device_path *, +- const struct ppp_channel *); ++ struct net_device_path *, ++ const struct ppp_channel *); + }; + + struct ppp_channel { +@@ -76,6 +90,51 @@ extern int ppp_unit_number(struct ppp_ch + /* Get the device name associated with a channel, or NULL if none */ + extern char *ppp_dev_name(struct ppp_channel *); + ++/* Call this to obtain the underlying protocol of the PPP channel, ++ * e.g. PX_PROTO_OE ++ */ ++extern int ppp_channel_get_protocol(struct ppp_channel *); ++ ++/* Call this get protocol version */ ++extern int ppp_channel_get_proto_version(struct ppp_channel *); ++ ++/* Call this to hold a channel */ ++extern bool ppp_channel_hold(struct ppp_channel *); ++ ++/* Call this to release a hold you have upon a channel */ ++extern void ppp_channel_release(struct ppp_channel *); ++ ++/* Release hold on PPP channels */ ++extern void ppp_release_channels(struct ppp_channel *channels[], ++ unsigned int chan_sz); ++ ++/* Hold PPP channels for the PPP device */ ++extern int ppp_hold_channels(struct net_device *dev, ++ struct ppp_channel *channels[], ++ unsigned int chan_sz); ++ ++/* Test if ppp xmit lock is locked */ ++extern bool ppp_is_xmit_locked(struct net_device *dev); ++ ++/* Test if the ppp device is a multi-link ppp device */ ++extern int ppp_is_multilink(struct net_device *dev); ++ ++/* Register the PPP channel connect notifier */ ++extern void ppp_channel_connection_register_notify(struct notifier_block *nb); ++ ++/* Unregister the PPP channel connect notifier */ ++extern void ppp_channel_connection_unregister_notify(struct notifier_block *nb); ++ ++/* Update statistics of the PPP net_device by incrementing related ++ * statistics field value with corresponding parameter ++ */ ++extern void ppp_update_stats(struct net_device *dev, unsigned long rx_packets, ++ unsigned long rx_bytes, unsigned long tx_packets, ++ unsigned long tx_bytes, unsigned long rx_errors, ++ unsigned long tx_errors, unsigned long rx_dropped, ++ unsigned long tx_dropped); ++ ++ + /* + * SMP locking notes: + * The channel code must ensure that when it calls ppp_unregister_channel, diff --git a/6.6/target/linux/qualcommax/patches-6.6/0600-3-qca-nss-ecm-support-net-bonding.patch b/6.6/target/linux/qualcommax/patches-6.6/0600-3-qca-nss-ecm-support-net-bonding.patch new file mode 100644 index 000000000..4e683e3a3 --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0600-3-qca-nss-ecm-support-net-bonding.patch @@ -0,0 +1,46 @@ +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -210,6 +210,7 @@ atomic_t netpoll_block_tx = ATOMIC_INIT( + #endif + + unsigned int bond_net_id __read_mostly; ++static unsigned long bond_id_mask = 0xFFFFFFF0; /* QCA NSS ECM bonding support */ + + static const struct flow_dissector_key flow_keys_bonding_keys[] = { + { +@@ -5872,6 +5873,11 @@ static void bond_destructor(struct net_d + if (bond->wq) + destroy_workqueue(bond->wq); + ++ /* QCA NSS ECM bonding support - Start */ ++ if (bond->id != (~0U)) ++ clear_bit(bond->id, &bond_id_mask); ++ /* QCA NSS ECM bonding support - End */ ++ + free_percpu(bond->rr_tx_counter); + } + +@@ -6421,6 +6427,13 @@ int bond_create(struct net *net, const c + + bond_work_init_all(bond); + ++ /* QCA NSS ECM bonding support - Start */ ++ bond->id = ~0U; ++ if (bond_id_mask != (~0UL)) { ++ bond->id = (u32)ffz(bond_id_mask); ++ set_bit(bond->id, &bond_id_mask); ++ } ++ /* QCA NSS ECM bonding support - End */ + out: + rtnl_unlock(); + return res; +--- a/include/net/bonding.h ++++ b/include/net/bonding.h +@@ -261,6 +261,7 @@ struct bonding { + spinlock_t ipsec_lock; + #endif /* CONFIG_XFRM_OFFLOAD */ + struct bpf_prog *xdp_prog; ++ u32 id;/* QCA NSS ECM bonding support */ + }; + + #define bond_slave_get_rcu(dev) \ diff --git a/6.6/target/linux/qualcommax/patches-6.6/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch b/6.6/target/linux/qualcommax/patches-6.6/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch new file mode 100644 index 000000000..e02e9090d --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0600-4-qca-nss-ecm-support-net-bonding-over-LAG-interface.patch @@ -0,0 +1,685 @@ +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -116,6 +116,40 @@ static void ad_marker_response_received( + struct port *port); + static void ad_update_actor_keys(struct port *port, bool reset); + ++/* QCA NSS ECM bonding support - Start */ ++struct bond_cb __rcu *bond_cb; ++ ++int bond_register_cb(struct bond_cb *cb) ++{ ++ struct bond_cb *lag_cb; ++ ++ lag_cb = kzalloc(sizeof(*lag_cb), GFP_ATOMIC | __GFP_NOWARN); ++ if (!lag_cb) { ++ return -1; ++ } ++ ++ memcpy((void *)lag_cb, (void *)cb, sizeof(*cb)); ++ ++ rcu_read_lock(); ++ rcu_assign_pointer(bond_cb, lag_cb); ++ rcu_read_unlock(); ++ return 0; ++} ++EXPORT_SYMBOL(bond_register_cb); ++ ++void bond_unregister_cb(void) ++{ ++ struct bond_cb *lag_cb_main; ++ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ rcu_assign_pointer(bond_cb, NULL); ++ rcu_read_unlock(); ++ ++ kfree(lag_cb_main); ++} ++EXPORT_SYMBOL(bond_unregister_cb); ++/* QCA NSS ECM bonding support - End */ + + /* ================= api to bonding and kernel code ================== */ + +@@ -1073,7 +1107,31 @@ static void ad_mux_machine(struct port * + ad_disable_collecting_distributing(port, + update_slave_arr); + port->ntt = true; ++ ++ /* QCA NSS ECM bonding support - Start */ ++ /* Send a notificaton about change in state of this ++ * port. We only want to handle case where port moves ++ * from AD_MUX_COLLECTING_DISTRIBUTING -> ++ * AD_MUX_ATTACHED. ++ */ ++ if (bond_slave_is_up(port->slave) && ++ (last_state == AD_MUX_COLLECTING_DISTRIBUTING)) { ++ struct bond_cb *lag_cb_main; ++ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ if (lag_cb_main && ++ lag_cb_main->bond_cb_link_down) { ++ struct net_device *dev; ++ ++ dev = port->slave->dev; ++ lag_cb_main->bond_cb_link_down(dev); ++ } ++ rcu_read_unlock(); ++ } ++ + break; ++ /* QCA NSS ECM bonding support - End */ + case AD_MUX_COLLECTING_DISTRIBUTING: + port->actor_oper_port_state |= LACP_STATE_COLLECTING; + port->actor_oper_port_state |= LACP_STATE_DISTRIBUTING; +@@ -1917,6 +1975,7 @@ static void ad_enable_collecting_distrib + bool *update_slave_arr) + { + if (port->aggregator->is_active) { ++ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */ + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Enabling port %d (LAG %d)\n", + port->actor_port_number, +@@ -1924,6 +1983,16 @@ static void ad_enable_collecting_distrib + __enable_port(port); + /* Slave array needs update */ + *update_slave_arr = true; ++ ++ /* QCA NSS ECM bonding support - Start */ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ ++ if (lag_cb_main && lag_cb_main->bond_cb_link_up) ++ lag_cb_main->bond_cb_link_up(port->slave->dev); ++ ++ rcu_read_unlock(); ++ /* QCA NSS ECM bonding support - End */ + } + } + +@@ -2683,6 +2752,104 @@ int bond_3ad_get_active_agg_info(struct + return ret; + } + ++/* QCA NSS ECM bonding support - Start */ ++/* bond_3ad_get_tx_dev - Calculate egress interface for a given packet, ++ * for a LAG that is configured in 802.3AD mode ++ * @skb: pointer to skb to be egressed ++ * @src_mac: pointer to source L2 address ++ * @dst_mac: pointer to destination L2 address ++ * @src: pointer to source L3 address ++ * @dst: pointer to destination L3 address ++ * @protocol: L3 protocol id from L2 header ++ * @bond_dev: pointer to bond master device ++ * ++ * If @skb is NULL, bond_xmit_hash is used to calculate hash using L2/L3 ++ * addresses. ++ * ++ * Returns: Either valid slave device, or NULL otherwise ++ */ ++struct net_device *bond_3ad_get_tx_dev(struct sk_buff *skb, u8 *src_mac, ++ u8 *dst_mac, void *src, ++ void *dst, u16 protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr) ++{ ++ struct bonding *bond = netdev_priv(bond_dev); ++ struct aggregator *agg; ++ struct ad_info ad_info; ++ struct list_head *iter; ++ struct slave *slave; ++ struct slave *first_ok_slave = NULL; ++ u32 hash = 0; ++ int slaves_in_agg; ++ int slave_agg_no = 0; ++ int agg_id; ++ ++ if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { ++ pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n", ++ bond_dev->name); ++ return NULL; ++ } ++ ++ slaves_in_agg = ad_info.ports; ++ agg_id = ad_info.aggregator_id; ++ ++ if (slaves_in_agg == 0) { ++ pr_debug("%s: Error: active aggregator is empty\n", ++ bond_dev->name); ++ return NULL; ++ } ++ ++ if (skb) { ++ hash = bond_xmit_hash(bond, skb); ++ slave_agg_no = hash % slaves_in_agg; ++ } else { ++ if (bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER23 && ++ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER2 && ++ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER34) { ++ pr_debug("%s: Error: Unsupported hash policy for 802.3AD fast path\n", ++ bond_dev->name); ++ return NULL; ++ } ++ ++ hash = bond_xmit_hash_without_skb(src_mac, dst_mac, ++ src, dst, protocol, ++ bond_dev, layer4hdr); ++ slave_agg_no = hash % slaves_in_agg; ++ } ++ ++ bond_for_each_slave_rcu(bond, slave, iter) { ++ agg = SLAVE_AD_INFO(slave)->port.aggregator; ++ if (!agg || agg->aggregator_identifier != agg_id) ++ continue; ++ ++ if (slave_agg_no >= 0) { ++ if (!first_ok_slave && bond_slave_can_tx(slave)) ++ first_ok_slave = slave; ++ slave_agg_no--; ++ continue; ++ } ++ ++ if (bond_slave_can_tx(slave)) ++ return slave->dev; ++ } ++ ++ if (slave_agg_no >= 0) { ++ pr_err("%s: Error: Couldn't find a slave to tx on for aggregator ID %d\n", ++ bond_dev->name, agg_id); ++ return NULL; ++ } ++ ++ /* we couldn't find any suitable slave after the agg_no, so use the ++ * first suitable found, if found. ++ */ ++ if (first_ok_slave) ++ return first_ok_slave->dev; ++ ++ return NULL; ++} ++/* QCA NSS ECM bonding support - End */ ++ + int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond, + struct slave *slave) + { +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -288,6 +288,21 @@ const char *bond_mode_name(int mode) + return names[mode]; + } + ++/* QCA NSS ECM bonding support */ ++int bond_get_id(struct net_device *bond_dev) ++{ ++ struct bonding *bond; ++ ++ if (!((bond_dev->priv_flags & IFF_BONDING) && ++ (bond_dev->flags & IFF_MASTER))) ++ return -EINVAL; ++ ++ bond = netdev_priv(bond_dev); ++ return bond->id; ++} ++EXPORT_SYMBOL(bond_get_id); ++/* QCA NSS ECM bonding support */ ++ + /** + * bond_dev_queue_xmit - Prepare skb for xmit. + * +@@ -1189,6 +1204,23 @@ void bond_change_active_slave(struct bon + if (BOND_MODE(bond) == BOND_MODE_8023AD) + bond_3ad_handle_link_change(new_active, BOND_LINK_UP); + ++ /* QCA NSS ECM bonding support - Start */ ++ if (bond->params.mode == BOND_MODE_XOR) { ++ struct bond_cb *lag_cb_main; ++ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ if (lag_cb_main && ++ lag_cb_main->bond_cb_link_up) { ++ struct net_device *dev; ++ ++ dev = new_active->dev; ++ lag_cb_main->bond_cb_link_up(dev); ++ } ++ rcu_read_unlock(); ++ } ++ /* QCA NSS ECM bonding support - End */ ++ + if (bond_is_lb(bond)) + bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); + } else { +@@ -1833,6 +1865,7 @@ int bond_enslave(struct net_device *bond + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; + struct slave *new_slave = NULL, *prev_slave; + struct sockaddr_storage ss; ++ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */ + int link_reporting; + int res = 0, i; + +@@ -2278,6 +2311,15 @@ int bond_enslave(struct net_device *bond + bond_is_active_slave(new_slave) ? "an active" : "a backup", + new_slave->link != BOND_LINK_DOWN ? "an up" : "a down"); + ++ /* QCA NSS ECM bonding support - Start */ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ if (lag_cb_main && lag_cb_main->bond_cb_enslave) ++ lag_cb_main->bond_cb_enslave(slave_dev); ++ ++ rcu_read_unlock(); ++ /* QCA NSS ECM bonding support - End */ ++ + /* enslave is successful */ + bond_queue_slave_event(new_slave); + return 0; +@@ -2343,6 +2385,15 @@ err_undo_flags: + } + } + ++ /* QCA NSS ECM bonding support - Start */ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ if (lag_cb_main && lag_cb_main->bond_cb_enslave) ++ lag_cb_main->bond_cb_enslave(slave_dev); ++ ++ rcu_read_unlock(); ++ /* QCA NSS ECM bonding support - End */ ++ + return res; + } + +@@ -2364,6 +2415,7 @@ static int __bond_release_one(struct net + struct bonding *bond = netdev_priv(bond_dev); + struct slave *slave, *oldcurrent; + struct sockaddr_storage ss; ++ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */ + int old_flags = bond_dev->flags; + netdev_features_t old_features = bond_dev->features; + +@@ -2386,6 +2438,15 @@ static int __bond_release_one(struct net + + bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW); + ++ /* QCA NSS ECM bonding support - Start */ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ if (lag_cb_main && lag_cb_main->bond_cb_release) ++ lag_cb_main->bond_cb_release(slave_dev); ++ ++ rcu_read_unlock(); ++ /* QCA NSS ECM bonding support - End */ ++ + bond_sysfs_slave_del(slave); + + /* recompute stats just before removing the slave */ +@@ -2708,6 +2769,8 @@ static void bond_miimon_commit(struct bo + struct slave *slave, *primary, *active; + bool do_failover = false; + struct list_head *iter; ++ struct net_device *slave_dev = NULL; /* QCA NSS ECM bonding support */ ++ struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */ + + ASSERT_RTNL(); + +@@ -2747,6 +2810,12 @@ static void bond_miimon_commit(struct bo + bond_set_active_slave(slave); + } + ++ /* QCA NSS ECM bonding support - Start */ ++ if ((bond->params.mode == BOND_MODE_XOR) && ++ (!slave_dev)) ++ slave_dev = slave->dev; ++ /* QCA NSS ECM bonding support - End */ ++ + slave_info(bond->dev, slave->dev, "link status definitely up, %u Mbps %s duplex\n", + slave->speed == SPEED_UNKNOWN ? 0 : slave->speed, + slave->duplex ? "full" : "half"); +@@ -2795,6 +2864,16 @@ static void bond_miimon_commit(struct bo + unblock_netpoll_tx(); + } + ++ /* QCA NSS ECM bonding support - Start */ ++ rcu_read_lock(); ++ lag_cb_main = rcu_dereference(bond_cb); ++ ++ if (slave_dev && lag_cb_main && lag_cb_main->bond_cb_link_up) ++ lag_cb_main->bond_cb_link_up(slave_dev); ++ ++ rcu_read_unlock(); ++ /* QCA NSS ECM bonding support - End */ ++ + bond_set_carrier(bond); + } + +@@ -4047,8 +4126,219 @@ static inline u32 bond_eth_hash(struct s + return 0; + + ep = (struct ethhdr *)(data + mhoff); +- return ep->h_dest[5] ^ ep->h_source[5] ^ be16_to_cpu(ep->h_proto); ++ return ep->h_dest[5] ^ ep->h_source[5]; /* QCA NSS ECM bonding support */ ++} ++ ++/* QCA NSS ECM bonding support - Start */ ++/* Extract the appropriate headers based on bond's xmit policy */ ++static bool bond_flow_dissect_without_skb(struct bonding *bond, ++ u8 *src_mac, u8 *dst_mac, ++ void *psrc, void *pdst, ++ u16 protocol, __be16 *layer4hdr, ++ struct flow_keys *fk) ++{ ++ u32 *src = NULL; ++ u32 *dst = NULL; ++ ++ fk->ports.ports = 0; ++ src = (uint32_t *)psrc; ++ dst = (uint32_t *)pdst; ++ ++ if (protocol == htons(ETH_P_IP)) { ++ /* V4 addresses and address type*/ ++ fk->addrs.v4addrs.src = src[0]; ++ fk->addrs.v4addrs.dst = dst[0]; ++ fk->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; ++ } else if (protocol == htons(ETH_P_IPV6)) { ++ /* V6 addresses and address type*/ ++ memcpy(&fk->addrs.v6addrs.src, src, sizeof(struct in6_addr)); ++ memcpy(&fk->addrs.v6addrs.dst, dst, sizeof(struct in6_addr)); ++ fk->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; ++ } else { ++ return false; ++ } ++ if ((bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34) && ++ (layer4hdr)) ++ fk->ports.ports = *layer4hdr; ++ ++ return true; ++} ++ ++/* bond_xmit_hash_without_skb - Applies load balancing algorithm for a packet, ++ * to calculate hash for a given set of L2/L3 addresses. Does not ++ * calculate egress interface. ++ */ ++uint32_t bond_xmit_hash_without_skb(u8 *src_mac, u8 *dst_mac, ++ void *psrc, void *pdst, u16 protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr) ++{ ++ struct bonding *bond = netdev_priv(bond_dev); ++ struct flow_keys flow; ++ u32 hash = 0; ++ ++ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER2 || ++ !bond_flow_dissect_without_skb(bond, src_mac, dst_mac, psrc, ++ pdst, protocol, layer4hdr, &flow)) ++ return (dst_mac[5] ^ src_mac[5]); ++ ++ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23) ++ hash = dst_mac[5] ^ src_mac[5]; ++ else if (layer4hdr) ++ hash = (__force u32)flow.ports.ports; ++ ++ hash ^= (__force u32)flow_get_u32_dst(&flow) ^ ++ (__force u32)flow_get_u32_src(&flow); ++ hash ^= (hash >> 16); ++ hash ^= (hash >> 8); ++ ++ return hash; ++} ++ ++/* bond_xor_get_tx_dev - Calculate egress interface for a given packet for a LAG ++ * that is configured in balance-xor mode ++ * @skb: pointer to skb to be egressed ++ * @src_mac: pointer to source L2 address ++ * @dst_mac: pointer to destination L2 address ++ * @src: pointer to source L3 address in network order ++ * @dst: pointer to destination L3 address in network order ++ * @protocol: L3 protocol ++ * @bond_dev: pointer to bond master device ++ * ++ * If @skb is NULL, bond_xmit_hash_without_skb is used to calculate hash using ++ * L2/L3 addresses. ++ * ++ * Returns: Either valid slave device, or NULL otherwise ++ */ ++static struct net_device *bond_xor_get_tx_dev(struct sk_buff *skb, ++ u8 *src_mac, u8 *dst_mac, ++ void *src, void *dst, ++ u16 protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr) ++{ ++ struct bonding *bond = netdev_priv(bond_dev); ++ int slave_cnt = READ_ONCE(bond->slave_cnt); ++ int slave_id = 0, i = 0; ++ u32 hash; ++ struct list_head *iter; ++ struct slave *slave; ++ ++ if (slave_cnt == 0) { ++ pr_debug("%s: Error: No slave is attached to the interface\n", ++ bond_dev->name); ++ return NULL; ++ } ++ ++ if (skb) { ++ hash = bond_xmit_hash(bond, skb); ++ slave_id = hash % slave_cnt; ++ } else { ++ if (bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER23 && ++ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER2 && ++ bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER34) { ++ pr_debug("%s: Error: Unsupported hash policy for balance-XOR fast path\n", ++ bond_dev->name); ++ return NULL; ++ } ++ ++ hash = bond_xmit_hash_without_skb(src_mac, dst_mac, src, ++ dst, protocol, bond_dev, ++ layer4hdr); ++ slave_id = hash % slave_cnt; ++ } ++ ++ i = slave_id; ++ ++ /* Here we start from the slave with slave_id */ ++ bond_for_each_slave_rcu(bond, slave, iter) { ++ if (--i < 0) { ++ if (bond_slave_can_tx(slave)) ++ return slave->dev; ++ } ++ } ++ ++ /* Here we start from the first slave up to slave_id */ ++ i = slave_id; ++ bond_for_each_slave_rcu(bond, slave, iter) { ++ if (--i < 0) ++ break; ++ if (bond_slave_can_tx(slave)) ++ return slave->dev; ++ } ++ ++ return NULL; ++} ++ ++/* bond_get_tx_dev - Calculate egress interface for a given packet. ++ * ++ * Supports 802.3AD and balance-xor modes ++ * ++ * @skb: pointer to skb to be egressed, if valid ++ * @src_mac: pointer to source L2 address ++ * @dst_mac: pointer to destination L2 address ++ * @src: pointer to source L3 address in network order ++ * @dst: pointer to destination L3 address in network order ++ * @protocol: L3 protocol id from L2 header ++ * @bond_dev: pointer to bond master device ++ * ++ * Returns: Either valid slave device, or NULL for un-supported LAG modes ++ */ ++struct net_device *bond_get_tx_dev(struct sk_buff *skb, uint8_t *src_mac, ++ u8 *dst_mac, void *src, ++ void *dst, u16 protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr) ++{ ++ struct bonding *bond; ++ ++ if (!bond_dev) ++ return NULL; ++ ++ if (!((bond_dev->priv_flags & IFF_BONDING) && ++ (bond_dev->flags & IFF_MASTER))) ++ return NULL; ++ ++ bond = netdev_priv(bond_dev); ++ ++ switch (bond->params.mode) { ++ case BOND_MODE_XOR: ++ return bond_xor_get_tx_dev(skb, src_mac, dst_mac, ++ src, dst, protocol, ++ bond_dev, layer4hdr); ++ case BOND_MODE_8023AD: ++ return bond_3ad_get_tx_dev(skb, src_mac, dst_mac, ++ src, dst, protocol, ++ bond_dev, layer4hdr); ++ default: ++ return NULL; ++ } + } ++EXPORT_SYMBOL(bond_get_tx_dev); ++ ++/* In bond_xmit_xor() , we determine the output device by using a pre- ++ * determined xmit_hash_policy(), If the selected device is not enabled, ++ * find the next active slave. ++ */ ++static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct bonding *bond = netdev_priv(dev); ++ struct net_device *outdev; ++ ++ outdev = bond_xor_get_tx_dev(skb, NULL, NULL, NULL, ++ NULL, 0, dev, NULL); ++ if (!outdev) ++ goto out; ++ ++ bond_dev_queue_xmit(bond, skb, outdev); ++ goto final; ++out: ++ /* no suitable interface, frame not sent */ ++ dev_kfree_skb(skb); ++final: ++ return NETDEV_TX_OK; ++} ++/* QCA NSS ECM bonding support - End */ + + static bool bond_flow_ip(struct sk_buff *skb, struct flow_keys *fk, const void *data, + int hlen, __be16 l2_proto, int *nhoff, int *ip_proto, bool l34) +@@ -5177,15 +5467,18 @@ static netdev_tx_t bond_3ad_xor_xmit(str + struct net_device *dev) + { + struct bonding *bond = netdev_priv(dev); +- struct bond_up_slave *slaves; +- struct slave *slave; ++ /* QCA NSS ECM bonding support - Start */ ++ struct net_device *outdev = NULL; + +- slaves = rcu_dereference(bond->usable_slaves); +- slave = bond_xmit_3ad_xor_slave_get(bond, skb, slaves); +- if (likely(slave)) +- return bond_dev_queue_xmit(bond, skb, slave->dev); ++ outdev = bond_3ad_get_tx_dev(skb, NULL, NULL, NULL, ++ NULL, 0, dev, NULL); ++ if (!outdev) { ++ dev_kfree_skb(skb); ++ return NETDEV_TX_OK; ++ } + +- return bond_tx_drop(dev, skb); ++ return bond_dev_queue_xmit(bond, skb, outdev); ++ /* QCA NSS ECM bonding support - End */ + } + + /* in broadcast mode, we send everything to all usable interfaces. */ +@@ -5435,8 +5728,9 @@ static netdev_tx_t __bond_start_xmit(str + return bond_xmit_roundrobin(skb, dev); + case BOND_MODE_ACTIVEBACKUP: + return bond_xmit_activebackup(skb, dev); +- case BOND_MODE_8023AD: + case BOND_MODE_XOR: ++ return bond_xmit_xor(skb, dev); /* QCA NSS ECM bonding support */ ++ case BOND_MODE_8023AD: + return bond_3ad_xor_xmit(skb, dev); + case BOND_MODE_BROADCAST: + return bond_xmit_broadcast(skb, dev); +--- a/include/net/bond_3ad.h ++++ b/include/net/bond_3ad.h +@@ -302,8 +302,15 @@ int bond_3ad_lacpdu_recv(const struct sk + struct slave *slave); + int bond_3ad_set_carrier(struct bonding *bond); + void bond_3ad_update_lacp_rate(struct bonding *bond); ++/* QCA NSS ECM bonding support */ ++struct net_device *bond_3ad_get_tx_dev(struct sk_buff *skb, uint8_t *src_mac, ++ uint8_t *dst_mac, void *src, ++ void *dst, uint16_t protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr); ++/* QCA NSS ECM bonding support */ ++ + void bond_3ad_update_ad_actor_settings(struct bonding *bond); + int bond_3ad_stats_fill(struct sk_buff *skb, struct bond_3ad_stats *stats); + size_t bond_3ad_stats_size(void); + #endif /* _NET_BOND_3AD_H */ +- +--- a/include/net/bonding.h ++++ b/include/net/bonding.h +@@ -90,6 +90,8 @@ + #define BOND_XFRM_FEATURES (NETIF_F_HW_ESP | NETIF_F_HW_ESP_TX_CSUM | \ + NETIF_F_GSO_ESP) + ++extern struct bond_cb __rcu *bond_cb; /* QCA NSS ECM bonding support */ ++ + #ifdef CONFIG_NET_POLL_CONTROLLER + extern atomic_t netpoll_block_tx; + +@@ -653,6 +655,7 @@ struct bond_net { + + int bond_rcv_validate(const struct sk_buff *skb, struct bonding *bond, struct slave *slave); + netdev_tx_t bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); ++int bond_get_id(struct net_device *bond_dev); /* QCA NSS ECM bonding support */ + int bond_create(struct net *net, const char *name); + int bond_create_sysfs(struct bond_net *net); + void bond_destroy_sysfs(struct bond_net *net); +@@ -684,6 +687,13 @@ struct bond_vlan_tag *bond_verify_device + int level); + int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave); + void bond_slave_arr_work_rearm(struct bonding *bond, unsigned long delay); ++/* QCA NSS ECM bonding support - Start */ ++uint32_t bond_xmit_hash_without_skb(uint8_t *src_mac, uint8_t *dst_mac, ++ void *psrc, void *pdst, uint16_t protocol, ++ struct net_device *bond_dev, ++ __be16 *layer4hdr); ++/* QCA NSS ECM bonding support - End */ ++ + void bond_work_init_all(struct bonding *bond); + + #ifdef CONFIG_PROC_FS +@@ -788,4 +798,18 @@ static inline netdev_tx_t bond_tx_drop(s + return NET_XMIT_DROP; + } + ++/* QCA NSS ECM bonding support - Start */ ++struct bond_cb { ++ void (*bond_cb_link_up)(struct net_device *slave); ++ void (*bond_cb_link_down)(struct net_device *slave); ++ void (*bond_cb_enslave)(struct net_device *slave); ++ void (*bond_cb_release)(struct net_device *slave); ++ void (*bond_cb_delete_by_slave)(struct net_device *slave); ++ void (*bond_cb_delete_by_mac)(uint8_t *mac_addr); ++}; ++ ++extern int bond_register_cb(struct bond_cb *cb); ++extern void bond_unregister_cb(void); ++/* QCA NSS ECM bonding support - End */ ++ + #endif /* _NET_BONDING_H */ diff --git a/6.6/target/linux/qualcommax/patches-6.6/0600-5-qca-nss-ecm-support-macvlan.patch b/6.6/target/linux/qualcommax/patches-6.6/0600-5-qca-nss-ecm-support-macvlan.patch new file mode 100644 index 000000000..29f7e96d7 --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0600-5-qca-nss-ecm-support-macvlan.patch @@ -0,0 +1,96 @@ +--- a/include/linux/if_macvlan.h ++++ b/include/linux/if_macvlan.h +@@ -15,6 +15,13 @@ struct macvlan_port; + #define MACVLAN_MC_FILTER_BITS 8 + #define MACVLAN_MC_FILTER_SZ (1 << MACVLAN_MC_FILTER_BITS) + ++/* QCA NSS ECM Support - Start */ ++/* ++ * Callback for updating interface statistics for macvlan flows offloaded from host CPU. ++ */ ++typedef void (*macvlan_offload_stats_update_cb_t)(struct net_device *dev, struct rtnl_link_stats64 *stats, bool update_mcast_rx_stats); ++/* QCA NSS ECM Support - End */ ++ + struct macvlan_dev { + struct net_device *dev; + struct list_head list; +@@ -35,6 +42,7 @@ struct macvlan_dev { + #ifdef CONFIG_NET_POLL_CONTROLLER + struct netpoll *netpoll; + #endif ++ macvlan_offload_stats_update_cb_t offload_stats_update; /* QCA NSS ECM support */ + }; + + static inline void macvlan_count_rx(const struct macvlan_dev *vlan, +@@ -107,4 +115,26 @@ static inline int macvlan_release_l2fw_o + macvlan->accel_priv = NULL; + return dev_uc_add(macvlan->lowerdev, dev->dev_addr); + } ++ ++/* QCA NSS ECM Support - Start */ ++#if IS_ENABLED(CONFIG_MACVLAN) ++static inline void ++macvlan_offload_stats_update(struct net_device *dev, ++ struct rtnl_link_stats64 *stats, ++ bool update_mcast_rx_stats) ++{ ++ struct macvlan_dev *macvlan = netdev_priv(dev); ++ ++ macvlan->offload_stats_update(dev, stats, update_mcast_rx_stats); ++} ++ ++static inline enum ++macvlan_mode macvlan_get_mode(struct net_device *dev) ++{ ++ struct macvlan_dev *macvlan = netdev_priv(dev); ++ ++ return macvlan->mode; ++} ++#endif ++/* QCA NSS ECM Support - End */ + #endif /* _LINUX_IF_MACVLAN_H */ +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -960,6 +960,34 @@ static void macvlan_uninit(struct net_de + macvlan_port_destroy(port->dev); + } + ++/* QCA NSS ECM Support - Start */ ++/* Update macvlan statistics processed by offload engines */ ++static void macvlan_dev_update_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *offl_stats, ++ bool update_mcast_rx_stats) ++{ ++ struct vlan_pcpu_stats *stats; ++ struct macvlan_dev *macvlan; ++ ++ /* Is this a macvlan? */ ++ if (!netif_is_macvlan(dev)) ++ return; ++ ++ macvlan = netdev_priv(dev); ++ stats = this_cpu_ptr(macvlan->pcpu_stats); ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_add(&stats->rx_packets, offl_stats->rx_packets); ++ u64_stats_add(&stats->rx_bytes, offl_stats->rx_bytes); ++ u64_stats_add(&stats->tx_packets, offl_stats->tx_packets); ++ u64_stats_add(&stats->tx_bytes, offl_stats->tx_bytes); ++ /* Update multicast statistics */ ++ if (unlikely(update_mcast_rx_stats)) { ++ u64_stats_add(&stats->rx_multicast, offl_stats->rx_packets); ++ } ++ u64_stats_update_end(&stats->syncp); ++} ++/* QCA NSS ECM Support - End */ ++ + static void macvlan_dev_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) + { +@@ -1506,6 +1534,7 @@ int macvlan_common_newlink(struct net *s + vlan->dev = dev; + vlan->port = port; + vlan->set_features = MACVLAN_FEATURES; ++ vlan->offload_stats_update = macvlan_dev_update_stats; /* QCA NSS ECM Support */ + + vlan->mode = MACVLAN_MODE_VEPA; + if (data && data[IFLA_MACVLAN_MODE]) diff --git a/6.6/target/linux/qualcommax/patches-6.6/0600-6-qca-nss-ecm-support-netfilter-DSCPREMARK.patch b/6.6/target/linux/qualcommax/patches-6.6/0600-6-qca-nss-ecm-support-netfilter-DSCPREMARK.patch new file mode 100644 index 000000000..27650731a --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0600-6-qca-nss-ecm-support-netfilter-DSCPREMARK.patch @@ -0,0 +1,154 @@ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -174,6 +174,13 @@ config NF_CONNTRACK_TIMEOUT + + If unsure, say `N'. + ++config NF_CONNTRACK_DSCPREMARK_EXT ++ bool 'Connection tracking extension for dscp remark target' ++ depends on NETFILTER_ADVANCED ++ help ++ This option enables support for connection tracking extension ++ for dscp remark. ++ + config NF_CONNTRACK_TIMESTAMP + bool 'Connection tracking timestamping' + depends on NETFILTER_ADVANCED +--- a/include/net/netfilter/nf_conntrack_extend.h ++++ b/include/net/netfilter/nf_conntrack_extend.h +@@ -31,6 +31,10 @@ enum nf_ct_ext_id { + #if IS_ENABLED(CONFIG_NET_ACT_CT) + NF_CT_EXT_ACT_CT, + #endif ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ NF_CT_EXT_DSCPREMARK, /* QCA NSS ECM support */ ++#endif ++ + NF_CT_EXT_NUM, + }; + +--- a/net/netfilter/nf_conntrack_extend.c ++++ b/net/netfilter/nf_conntrack_extend.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + + #define NF_CT_EXT_PREALLOC 128u /* conntrack events are on by default */ +@@ -54,6 +55,9 @@ static const u8 nf_ct_ext_type_len[NF_CT + #if IS_ENABLED(CONFIG_NET_ACT_CT) + [NF_CT_EXT_ACT_CT] = sizeof(struct nf_conn_act_ct_ext), + #endif ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ [NF_CT_EXT_DSCPREMARK] = sizeof(struct nf_ct_dscpremark_ext), ++#endif + }; + + static __always_inline unsigned int total_extension_size(void) +@@ -86,6 +90,9 @@ static __always_inline unsigned int tota + #if IS_ENABLED(CONFIG_NET_ACT_CT) + + sizeof(struct nf_conn_act_ct_ext) + #endif ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ + sizeof(struct nf_ct_dscpremark_ext) ++#endif + ; + } + +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -15,6 +15,7 @@ nf_conntrack-$(CONFIG_NF_CONNTRACK_OVS) + nf_conntrack-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o + nf_conntrack-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o + nf_conntrack-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o ++nf_conntrack-$(CONFIG_NF_CONNTRACK_DSCPREMARK_EXT) += nf_conntrack_dscpremark_ext.o + ifeq ($(CONFIG_NF_CONNTRACK),m) + nf_conntrack-$(CONFIG_DEBUG_INFO_BTF_MODULES) += nf_conntrack_bpf.o + else ifeq ($(CONFIG_NF_CONNTRACK),y) +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -45,6 +45,9 @@ + #include + #include + #include ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++#include ++#endif + #include + #include + #include +@@ -1740,6 +1743,9 @@ init_conntrack(struct net *net, struct n + nf_ct_acct_ext_add(ct, GFP_ATOMIC); + nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); + nf_ct_labels_ext_add(ct); ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ nf_ct_dscpremark_ext_add(ct, GFP_ATOMIC); ++#endif + + #ifdef CONFIG_NF_CONNTRACK_EVENTS + ecache = tmpl ? nf_ct_ecache_find(tmpl) : NULL; +--- a/net/netfilter/xt_DSCP.c ++++ b/net/netfilter/xt_DSCP.c +@@ -15,6 +15,9 @@ + + #include + #include ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++#include ++#endif + + MODULE_AUTHOR("Harald Welte "); + MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification"); +@@ -31,6 +34,10 @@ dscp_tg(struct sk_buff *skb, const struc + { + const struct xt_DSCP_info *dinfo = par->targinfo; + u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ struct nf_conn *ct; ++ enum ip_conntrack_info ctinfo; ++#endif + + if (dscp != dinfo->dscp) { + if (skb_ensure_writable(skb, sizeof(struct iphdr))) +@@ -39,6 +46,13 @@ dscp_tg(struct sk_buff *skb, const struc + ipv4_change_dsfield(ip_hdr(skb), XT_DSCP_ECN_MASK, + dinfo->dscp << XT_DSCP_SHIFT); + ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return XT_CONTINUE; ++ ++ nf_conntrack_dscpremark_ext_set_dscp_rule_valid(ct); ++#endif + } + return XT_CONTINUE; + } +@@ -48,13 +62,24 @@ dscp_tg6(struct sk_buff *skb, const stru + { + const struct xt_DSCP_info *dinfo = par->targinfo; + u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; +- ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ struct nf_conn *ct; ++ enum ip_conntrack_info ctinfo; ++#endif + if (dscp != dinfo->dscp) { + if (skb_ensure_writable(skb, sizeof(struct ipv6hdr))) + return NF_DROP; + + ipv6_change_dsfield(ipv6_hdr(skb), XT_DSCP_ECN_MASK, + dinfo->dscp << XT_DSCP_SHIFT); ++ ++#ifdef CONFIG_NF_CONNTRACK_DSCPREMARK_EXT ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return XT_CONTINUE; ++ ++ nf_conntrack_dscpremark_ext_set_dscp_rule_valid(ct); ++#endif + } + return XT_CONTINUE; + } diff --git a/6.6/target/linux/qualcommax/patches-6.6/0600-7-qca-nss-ecm-fix-IPv6-user-route-change-event-calls.patch b/6.6/target/linux/qualcommax/patches-6.6/0600-7-qca-nss-ecm-fix-IPv6-user-route-change-event-calls.patch new file mode 100644 index 000000000..e3081a79a --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0600-7-qca-nss-ecm-fix-IPv6-user-route-change-event-calls.patch @@ -0,0 +1,87 @@ +From ce18a6fdff6a39a01111d74f513d2ef66142047c Mon Sep 17 00:00:00 2001 +From: Murat Sezgin +Date: Wed, 5 Aug 2020 13:21:27 -0700 +Subject: [PATCH 246/281] net:ipv6: Fix IPv6 user route change event calls + +These events should be called only when the route table is +changed by the userspace. So, we should call them in the +ioctl and the netlink message handler function. + +Change-Id: If7ec615014cfc79d5fa72878e49eaf99c2560c32 +Signed-off-by: Murat Sezgin +--- + net/ipv6/route.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -3867,10 +3867,6 @@ int ip6_route_add(struct fib6_config *cf + return PTR_ERR(rt); + + err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack); +- if (!err) +- atomic_notifier_call_chain(&ip6route_chain, +- RTM_NEWROUTE, rt); +- + fib6_info_release(rt); + + return err; +@@ -3892,9 +3888,6 @@ static int __ip6_del_rt(struct fib6_info + err = fib6_del(rt, info); + spin_unlock_bh(&table->tb6_lock); + +- if (!err) +- atomic_notifier_call_chain(&ip6route_chain, +- RTM_DELROUTE, rt); + out: + fib6_info_release(rt); + return err; +@@ -4500,6 +4493,10 @@ int ipv6_route_ioctl(struct net *net, un + break; + } + rtnl_unlock(); ++ if (!err) ++ atomic_notifier_call_chain(&ip6route_chain, ++ (cmd == SIOCADDRT) ? RTM_NEWROUTE : RTM_DELROUTE, &cfg); ++ + return err; + } + +@@ -5518,11 +5515,17 @@ static int inet6_rtm_delroute(struct sk_ + } + + if (cfg.fc_mp) +- return ip6_route_multipath_del(&cfg, extack); ++ err = ip6_route_multipath_del(&cfg, extack); + else { + cfg.fc_delete_all_nh = 1; +- return ip6_route_del(&cfg, extack); ++ err = ip6_route_del(&cfg, extack); + } ++ ++ if (!err) ++ atomic_notifier_call_chain(&ip6route_chain, ++ RTM_DELROUTE, &cfg); ++ ++ return err; + } + + static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, +@@ -5539,9 +5542,15 @@ static int inet6_rtm_newroute(struct sk_ + cfg.fc_metric = IP6_RT_PRIO_USER; + + if (cfg.fc_mp) +- return ip6_route_multipath_add(&cfg, extack); ++ err = ip6_route_multipath_add(&cfg, extack); + else +- return ip6_route_add(&cfg, GFP_KERNEL, extack); ++ err = ip6_route_add(&cfg, GFP_KERNEL, extack); ++ ++ if (!err) ++ atomic_notifier_call_chain(&ip6route_chain, ++ RTM_NEWROUTE, &cfg); ++ ++ return err; + } + + /* add the overhead of this fib6_nh to nexthop_len */ diff --git a/6.6/target/linux/qualcommax/patches-6.6/0601-1-qca-add-nss-bridge-mgr-support.patch b/6.6/target/linux/qualcommax/patches-6.6/0601-1-qca-add-nss-bridge-mgr-support.patch new file mode 100644 index 000000000..dcfd78d59 --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0601-1-qca-add-nss-bridge-mgr-support.patch @@ -0,0 +1,92 @@ +From 3c17a0e1112be70071e98d5208da5b55dcec20a6 Mon Sep 17 00:00:00 2001 +From: Simon Casey +Date: Wed, 2 Feb 2022 19:37:29 +0100 +Subject: [PATCH] Update 607-qca-add-add-nss-bridge-mgr-support.patch for kernel 5.15 + +--- + include/linux/if_bridge.h | 4 ++++ + net/bridge/br_fdb.c | 25 +++++++++++++++++++++---- + 2 files changed, 25 insertions(+), 4 deletions(-) + +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -254,4 +254,8 @@ typedef struct net_bridge_port *br_get_d + extern br_get_dst_hook_t __rcu *br_get_dst_hook; + /* QCA NSS ECM support - End */ + ++/* QCA NSS bridge-mgr support - Start */ ++extern struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br); ++/* QCA NSS bridge-mgr support - End */ ++ + #endif +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -576,7 +576,7 @@ void br_fdb_cleanup(struct work_struct * + unsigned long delay = hold_time(br); + unsigned long work_delay = delay; + unsigned long now = jiffies; +- u8 mac_addr[6]; /* QCA NSS ECM support */ ++ struct br_fdb_event fdb_event; /* QCA NSS bridge-mgr support */ + + /* this part is tricky, in order to avoid blocking learning and + * consequently forwarding, we rely on rcu to delete objects with +@@ -604,12 +604,13 @@ void br_fdb_cleanup(struct work_struct * + } else { + spin_lock_bh(&br->hash_lock); + if (!hlist_unhashed(&f->fdb_node)) { +- ether_addr_copy(mac_addr, f->key.addr.addr); ++ memset(&fdb_event, 0, sizeof(fdb_event)); ++ ether_addr_copy(fdb_event.addr, f->key.addr.addr); + fdb_delete(br, f, true); + /* QCA NSS ECM support - Start */ + atomic_notifier_call_chain( + &br_fdb_update_notifier_list, 0, +- (void *)mac_addr); ++ (void *)&fdb_event); + /* QCA NSS ECM support - End */ + } + spin_unlock_bh(&br->hash_lock); +@@ -907,10 +908,21 @@ static bool __fdb_mark_active(struct net + test_and_clear_bit(BR_FDB_NOTIFY_INACTIVE, &fdb->flags)); + } + ++/* QCA NSS bridge-mgr support - Start */ ++/* Get the bridge device */ ++struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br) ++{ ++ dev_hold(br->dev); ++ return br->dev; ++} ++EXPORT_SYMBOL_GPL(br_fdb_bridge_dev_get_and_hold); ++/* QCA NSS bridge-mgr support - End */ ++ + void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, + const unsigned char *addr, u16 vid, unsigned long flags) + { + struct net_bridge_fdb_entry *fdb; ++ struct br_fdb_event fdb_event; /* QCA NSS bridge-mgr support */ + + /* some users want to always flood. */ + if (hold_time(br) == 0) +@@ -936,6 +948,12 @@ void br_fdb_update(struct net_bridge *br + if (unlikely(source != READ_ONCE(fdb->dst) && + !test_bit(BR_FDB_STICKY, &fdb->flags))) { + br_switchdev_fdb_notify(br, fdb, RTM_DELNEIGH); ++ /* QCA NSS bridge-mgr support - Start */ ++ ether_addr_copy(fdb_event.addr, addr); ++ fdb_event.br = br; ++ fdb_event.orig_dev = fdb->dst->dev; ++ fdb_event.dev = source->dev; ++ /* QCA NSS bridge-mgr support - End */ + WRITE_ONCE(fdb->dst, source); + fdb_modified = true; + /* Take over HW learned entry */ +@@ -952,7 +970,7 @@ void br_fdb_update(struct net_bridge *br + /* QCA NSS ECM support - Start */ + atomic_notifier_call_chain( + &br_fdb_update_notifier_list, +- 0, (void *)addr); ++ 0, (void *)&fdb_event); + /* QCA NSS ECM support - End */ + } + diff --git a/6.6/target/linux/qualcommax/patches-6.6/0602-1-qca-nss-drv-add-qdisc-support.patch b/6.6/target/linux/qualcommax/patches-6.6/0602-1-qca-nss-drv-add-qdisc-support.patch new file mode 100644 index 000000000..2926faace --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0602-1-qca-nss-drv-add-qdisc-support.patch @@ -0,0 +1,25 @@ +--- a/include/uapi/linux/pkt_cls.h ++++ b/include/uapi/linux/pkt_cls.h +@@ -139,6 +139,7 @@ enum tca_id { + TCA_ID_MPLS, + TCA_ID_CT, + TCA_ID_GATE, ++ TCA_ID_MIRRED_NSS, /* QCA NSS Qdisc IGS Support */ + /* other actions go here */ + __TCA_ID_MAX = 255 + }; +@@ -817,4 +818,14 @@ enum { + TCF_EM_OPND_LT + }; + ++/* QCA NSS Qdisc Support - Start */ ++#define _TC_MAKE32(x) ((x)) ++#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n)) ++ ++#define TC_NCLS _TC_MAKEMASK1(8) ++#define TC_NCLS_NSS _TC_MAKEMASK1(12) ++#define SET_TC_NCLS_NSS(v) ( TC_NCLS_NSS | ((v) & ~TC_NCLS_NSS)) ++#define CLR_TC_NCLS_NSS(v) ( (v) & ~TC_NCLS_NSS) ++/* QCA NSS Qdisc Support - End */ ++ + #endif diff --git a/6.6/target/linux/qualcommax/patches-6.6/0603-1-qca-nss-clients-add-qdisc-support.patch b/6.6/target/linux/qualcommax/patches-6.6/0603-1-qca-nss-clients-add-qdisc-support.patch new file mode 100644 index 000000000..9220aca1c --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0603-1-qca-nss-clients-add-qdisc-support.patch @@ -0,0 +1,463 @@ +--- a/include/linux/timer.h ++++ b/include/linux/timer.h +@@ -17,6 +17,7 @@ struct timer_list { + unsigned long expires; + void (*function)(struct timer_list *); + u32 flags; ++ unsigned long cust_data; + + #ifdef CONFIG_LOCKDEP + struct lockdep_map lockdep_map; +--- a/drivers/net/ifb.c ++++ b/drivers/net/ifb.c +@@ -151,6 +151,31 @@ resched: + + } + ++void ifb_update_offload_stats(struct net_device *dev, struct pcpu_sw_netstats *offload_stats) ++{ ++ struct ifb_dev_private *dp; ++ struct ifb_q_private *txp; ++ ++ if (!dev || !offload_stats) { ++ return; ++ } ++ ++ if (!(dev->priv_flags_ext & IFF_EXT_IFB)) { ++ return; ++ } ++ ++ dp = netdev_priv(dev); ++ txp = dp->tx_private; ++ ++ u64_stats_update_begin(&txp->rx_stats.sync); ++ txp->rx_stats.packets += u64_stats_read(&offload_stats->rx_packets); ++ txp->rx_stats.bytes += u64_stats_read(&offload_stats->rx_bytes); ++ txp->tx_stats.packets += u64_stats_read(&offload_stats->tx_packets); ++ txp->tx_stats.bytes += u64_stats_read(&offload_stats->tx_bytes); ++ u64_stats_update_end(&txp->rx_stats.sync); ++} ++EXPORT_SYMBOL(ifb_update_offload_stats); ++ + static void ifb_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) + { +@@ -326,6 +351,7 @@ static void ifb_setup(struct net_device + dev->flags |= IFF_NOARP; + dev->flags &= ~IFF_MULTICAST; + dev->priv_flags &= ~IFF_TX_SKB_SHARING; ++ dev->priv_flags_ext |= IFF_EXT_IFB; /* Mark the device as an IFB device. */ + netif_keep_dst(dev); + eth_hw_addr_random(dev); + dev->needs_free_netdev = true; +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -4696,6 +4696,15 @@ void dev_uc_flush(struct net_device *dev + void dev_uc_init(struct net_device *dev); + + /** ++ * ifb_update_offload_stats - Update the IFB interface stats ++ * @dev: IFB device to update the stats ++ * @offload_stats: per CPU stats structure ++ * ++ * Allows update of IFB stats when flows are offloaded to an accelerator. ++ **/ ++void ifb_update_offload_stats(struct net_device *dev, struct pcpu_sw_netstats *offload_stats); ++ ++/** + * __dev_uc_sync - Synchonize device's unicast list + * @dev: device to sync + * @sync: function to call if address should be added +@@ -5222,6 +5231,11 @@ static inline bool netif_is_failover_sla + return dev->priv_flags & IFF_FAILOVER_SLAVE; + } + ++static inline bool netif_is_ifb_dev(const struct net_device *dev) ++{ ++ return dev->priv_flags_ext & IFF_EXT_IFB; ++} ++ + /* This device needs to keep skb dst for qdisc enqueue or ndo_start_xmit() */ + static inline void netif_keep_dst(struct net_device *dev) + { +--- a/include/uapi/linux/pkt_sched.h ++++ b/include/uapi/linux/pkt_sched.h +@@ -1306,4 +1306,248 @@ enum { + + #define TCA_ETS_MAX (__TCA_ETS_MAX - 1) + ++/* QCA NSS Clients Support - Start */ ++enum { ++ TCA_NSS_ACCEL_MODE_NSS_FW, ++ TCA_NSS_ACCEL_MODE_PPE, ++ TCA_NSS_ACCEL_MODE_MAX ++}; ++ ++/* NSSFIFO section */ ++ ++enum { ++ TCA_NSSFIFO_UNSPEC, ++ TCA_NSSFIFO_PARMS, ++ __TCA_NSSFIFO_MAX ++}; ++ ++#define TCA_NSSFIFO_MAX (__TCA_NSSFIFO_MAX - 1) ++ ++struct tc_nssfifo_qopt { ++ __u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */ ++ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSWRED section */ ++ ++enum { ++ TCA_NSSWRED_UNSPEC, ++ TCA_NSSWRED_PARMS, ++ __TCA_NSSWRED_MAX ++}; ++ ++#define TCA_NSSWRED_MAX (__TCA_NSSWRED_MAX - 1) ++#define NSSWRED_CLASS_MAX 6 ++struct tc_red_alg_parameter { ++ __u32 min; /* qlen_avg < min: pkts are all enqueued */ ++ __u32 max; /* qlen_avg > max: pkts are all dropped */ ++ __u32 probability;/* Drop probability at qlen_avg = max */ ++ __u32 exp_weight_factor;/* exp_weight_factor for calculate qlen_avg */ ++}; ++ ++struct tc_nsswred_traffic_class { ++ __u32 limit; /* Queue length */ ++ __u32 weight_mode_value; /* Weight mode value */ ++ struct tc_red_alg_parameter rap;/* Parameters for RED alg */ ++}; ++ ++/* ++ * Weight modes for WRED ++ */ ++enum tc_nsswred_weight_modes { ++ TC_NSSWRED_WEIGHT_MODE_DSCP = 0,/* Weight mode is DSCP */ ++ TC_NSSWRED_WEIGHT_MODES, /* Must be last */ ++}; ++ ++struct tc_nsswred_qopt { ++ __u32 limit; /* Queue length */ ++ enum tc_nsswred_weight_modes weight_mode; ++ /* Weight mode */ ++ __u32 traffic_classes; /* How many traffic classes: DPs */ ++ __u32 def_traffic_class; /* Default traffic if no match: def_DP */ ++ __u32 traffic_id; /* The traffic id to be configured: DP */ ++ __u32 weight_mode_value; /* Weight mode value */ ++ struct tc_red_alg_parameter rap;/* RED algorithm parameters */ ++ struct tc_nsswred_traffic_class tntc[NSSWRED_CLASS_MAX]; ++ /* Traffic settings for dumpping */ ++ __u8 ecn; /* Setting ECN bit or dropping */ ++ __u8 set_default; /* Sets qdisc to be the default for enqueue */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSCODEL section */ ++ ++enum { ++ TCA_NSSCODEL_UNSPEC, ++ TCA_NSSCODEL_PARMS, ++ __TCA_NSSCODEL_MAX ++}; ++ ++#define TCA_NSSCODEL_MAX (__TCA_NSSCODEL_MAX - 1) ++ ++struct tc_nsscodel_qopt { ++ __u32 target; /* Acceptable queueing delay */ ++ __u32 limit; /* Max number of packets that can be held in the queue */ ++ __u32 interval; /* Monitoring interval */ ++ __u32 flows; /* Number of flow buckets */ ++ __u32 quantum; /* Weight (in bytes) used for DRR of flow buckets */ ++ __u8 ecn; /* 0 - disable ECN, 1 - enable ECN */ ++ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++struct tc_nsscodel_xstats { ++ __u32 peak_queue_delay; /* Peak delay experienced by a dequeued packet */ ++ __u32 peak_drop_delay; /* Peak delay experienced by a dropped packet */ ++}; ++ ++/* NSSFQ_CODEL section */ ++ ++struct tc_nssfq_codel_xstats { ++ __u32 new_flow_count; /* Total number of new flows seen */ ++ __u32 new_flows_len; /* Current number of new flows */ ++ __u32 old_flows_len; /* Current number of old flows */ ++ __u32 ecn_mark; /* Number of packets marked with ECN */ ++ __u32 drop_overlimit; /* Number of packets dropped due to overlimit */ ++ __u32 maxpacket; /* The largest packet seen so far in the queue */ ++}; ++ ++/* NSSTBL section */ ++ ++enum { ++ TCA_NSSTBL_UNSPEC, ++ TCA_NSSTBL_PARMS, ++ __TCA_NSSTBL_MAX ++}; ++ ++#define TCA_NSSTBL_MAX (__TCA_NSSTBL_MAX - 1) ++ ++struct tc_nsstbl_qopt { ++ __u32 burst; /* Maximum burst size */ ++ __u32 rate; /* Limiting rate of TBF */ ++ __u32 peakrate; /* Maximum rate at which TBF is allowed to send */ ++ __u32 mtu; /* Max size of packet, or minumim burst size */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSPRIO section */ ++ ++#define TCA_NSSPRIO_MAX_BANDS 256 ++ ++enum { ++ TCA_NSSPRIO_UNSPEC, ++ TCA_NSSPRIO_PARMS, ++ __TCA_NSSPRIO_MAX ++}; ++ ++#define TCA_NSSPRIO_MAX (__TCA_NSSPRIO_MAX - 1) ++ ++struct tc_nssprio_qopt { ++ __u32 bands; /* Number of bands */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSBF section */ ++ ++enum { ++ TCA_NSSBF_UNSPEC, ++ TCA_NSSBF_CLASS_PARMS, ++ TCA_NSSBF_QDISC_PARMS, ++ __TCA_NSSBF_MAX ++}; ++ ++#define TCA_NSSBF_MAX (__TCA_NSSBF_MAX - 1) ++ ++struct tc_nssbf_class_qopt { ++ __u32 burst; /* Maximum burst size */ ++ __u32 rate; /* Allowed bandwidth for this class */ ++ __u32 mtu; /* MTU of the associated interface */ ++ __u32 quantum; /* Quantum allocation for DRR */ ++}; ++ ++struct tc_nssbf_qopt { ++ __u16 defcls; /* Default class value */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSWRR section */ ++ ++enum { ++ TCA_NSSWRR_UNSPEC, ++ TCA_NSSWRR_CLASS_PARMS, ++ TCA_NSSWRR_QDISC_PARMS, ++ __TCA_NSSWRR_MAX ++}; ++ ++#define TCA_NSSWRR_MAX (__TCA_NSSWRR_MAX - 1) ++ ++struct tc_nsswrr_class_qopt { ++ __u32 quantum; /* Weight associated to this class */ ++}; ++ ++struct tc_nsswrr_qopt { ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSWFQ section */ ++ ++enum { ++ TCA_NSSWFQ_UNSPEC, ++ TCA_NSSWFQ_CLASS_PARMS, ++ TCA_NSSWFQ_QDISC_PARMS, ++ __TCA_NSSWFQ_MAX ++}; ++ ++#define TCA_NSSWFQ_MAX (__TCA_NSSWFQ_MAX - 1) ++ ++struct tc_nsswfq_class_qopt { ++ __u32 quantum; /* Weight associated to this class */ ++}; ++ ++struct tc_nsswfq_qopt { ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSHTB section */ ++ ++enum { ++ TCA_NSSHTB_UNSPEC, ++ TCA_NSSHTB_CLASS_PARMS, ++ TCA_NSSHTB_QDISC_PARMS, ++ __TCA_NSSHTB_MAX ++}; ++ ++#define TCA_NSSHTB_MAX (__TCA_NSSHTB_MAX - 1) ++ ++struct tc_nsshtb_class_qopt { ++ __u32 burst; /* Allowed burst size */ ++ __u32 rate; /* Allowed bandwidth for this class */ ++ __u32 cburst; /* Maximum burst size */ ++ __u32 crate; /* Maximum bandwidth for this class */ ++ __u32 quantum; /* Quantum allocation for DRR */ ++ __u32 priority; /* Priority value associated with this class */ ++ __u32 overhead; /* Overhead in bytes per packet */ ++}; ++ ++struct tc_nsshtb_qopt { ++ __u32 r2q; /* Rate to quantum ratio */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++ ++/* NSSBLACKHOLE section */ ++ ++enum { ++ TCA_NSSBLACKHOLE_UNSPEC, ++ TCA_NSSBLACKHOLE_PARMS, ++ __TCA_NSSBLACKHOLE_MAX ++}; ++ ++#define TCA_NSSBLACKHOLE_MAX (__TCA_NSSBLACKHOLE_MAX - 1) ++ ++struct tc_nssblackhole_qopt { ++ __u8 set_default; /* Sets qdisc to be the default qdisc for enqueue */ ++ __u8 accel_mode; /* Dictates which data plane offloads the qdisc */ ++}; ++/* QCA NSS Clients Support - End */ + #endif +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -314,6 +314,7 @@ struct Qdisc *qdisc_lookup(struct net_de + out: + return q; + } ++EXPORT_SYMBOL(qdisc_lookup); + + struct Qdisc *qdisc_lookup_rcu(struct net_device *dev, u32 handle) + { +@@ -2389,4 +2390,26 @@ static int __init pktsched_init(void) + return 0; + } + ++/* QCA NSS Qdisc Support - Start */ ++bool tcf_destroy(struct tcf_proto *tp, bool force) ++{ ++ tp->ops->destroy(tp, force, NULL); ++ module_put(tp->ops->owner); ++ kfree_rcu(tp, rcu); ++ ++ return true; ++} ++ ++void tcf_destroy_chain(struct tcf_proto __rcu **fl) ++{ ++ struct tcf_proto *tp; ++ ++ while ((tp = rtnl_dereference(*fl)) != NULL) { ++ RCU_INIT_POINTER(*fl, tp->next); ++ tcf_destroy(tp, true); ++ } ++} ++EXPORT_SYMBOL(tcf_destroy_chain); ++/* QCA NSS Qdisc Support - End */ ++ + subsys_initcall(pktsched_init); +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -1069,6 +1069,7 @@ static void __qdisc_destroy(struct Qdisc + + call_rcu(&qdisc->rcu, qdisc_free_cb); + } ++EXPORT_SYMBOL(qdisc_destroy); + + void qdisc_destroy(struct Qdisc *qdisc) + { +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -94,6 +94,7 @@ struct Qdisc { + #define TCQ_F_INVISIBLE 0x80 /* invisible by default in dump */ + #define TCQ_F_NOLOCK 0x100 /* qdisc does not require locking */ + #define TCQ_F_OFFLOADED 0x200 /* qdisc is offloaded to HW */ ++#define TCQ_F_NSS 0x1000 /* NSS qdisc flag. */ + u32 limit; + const struct Qdisc_ops *ops; + struct qdisc_size_table __rcu *stab; +@@ -751,6 +752,42 @@ static inline bool skb_skip_tc_classify( + return false; + } + ++/* QCA NSS Qdisc Support - Start */ ++/* ++ * Set skb classify bit field. ++ */ ++static inline void skb_set_tc_classify_offload(struct sk_buff *skb) ++{ ++#ifdef CONFIG_NET_CLS_ACT ++ skb->tc_skip_classify_offload = 1; ++#endif ++} ++ ++/* ++ * Clear skb classify bit field. ++ */ ++static inline void skb_clear_tc_classify_offload(struct sk_buff *skb) ++{ ++#ifdef CONFIG_NET_CLS_ACT ++ skb->tc_skip_classify_offload = 0; ++#endif ++} ++ ++/* ++ * Skip skb processing if sent from ifb dev. ++ */ ++static inline bool skb_skip_tc_classify_offload(struct sk_buff *skb) ++{ ++#ifdef CONFIG_NET_CLS_ACT ++ if (skb->tc_skip_classify_offload) { ++ skb_clear_tc_classify_offload(skb); ++ return true; ++ } ++#endif ++ return false; ++} ++/* QCA NSS Qdisc Support - End */ ++ + /* Reset all TX qdiscs greater than index of a device. */ + static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i) + { +@@ -1323,4 +1360,9 @@ static inline void qdisc_synchronize(con + msleep(1); + } + ++/* QCA NSS Qdisc Support - Start */ ++void qdisc_destroy(struct Qdisc *qdisc); ++void tcf_destroy_chain(struct tcf_proto __rcu **fl); ++/* QCA NSS Qdisc Support - End */ ++ + #endif +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -764,6 +764,7 @@ typedef unsigned char *sk_buff_data_t; + * @offload_fwd_mark: Packet was L2-forwarded in hardware + * @offload_l3_fwd_mark: Packet was L3-forwarded in hardware + * @tc_skip_classify: do not classify packet. set by IFB device ++ * @tc_skip_classify_offload: do not classify packet set by offload IFB device + * @tc_at_ingress: used within tc_classify to distinguish in/egress + * @redirected: packet was redirected by packet classifier + * @from_ingress: packet was redirected from the ingress path +@@ -945,6 +946,9 @@ struct sk_buff { + __u8 tc_at_ingress:1; /* See TC_AT_INGRESS_MASK */ + __u8 tc_skip_classify:1; + #endif ++#ifdef CONFIG_NET_CLS_ACT ++ __u8 tc_skip_classify_offload:1; /* QCA NSS Qdisc Support */ ++#endif + __u8 remcsum_offload:1; + __u8 csum_complete_sw:1; + __u8 csum_level:2; diff --git a/6.6/target/linux/qualcommax/patches-6.6/0603-2-qca-nss-clients-add-l2tp-support.patch b/6.6/target/linux/qualcommax/patches-6.6/0603-2-qca-nss-clients-add-l2tp-support.patch new file mode 100644 index 000000000..7fa9184df --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0603-2-qca-nss-clients-add-l2tp-support.patch @@ -0,0 +1,46 @@ +--- a/net/l2tp/l2tp_core.c ++++ b/net/l2tp/l2tp_core.c +@@ -398,6 +398,31 @@ err_tlock: + } + EXPORT_SYMBOL_GPL(l2tp_session_register); + ++void l2tp_stats_update(struct l2tp_tunnel *tunnel, ++ struct l2tp_session *session, ++ struct l2tp_stats *stats) ++{ ++ atomic_long_add(atomic_long_read(&stats->rx_packets), ++ &tunnel->stats.rx_packets); ++ atomic_long_add(atomic_long_read(&stats->rx_bytes), ++ &tunnel->stats.rx_bytes); ++ atomic_long_add(atomic_long_read(&stats->tx_packets), ++ &tunnel->stats.tx_packets); ++ atomic_long_add(atomic_long_read(&stats->tx_bytes), ++ &tunnel->stats.tx_bytes); ++ ++ atomic_long_add(atomic_long_read(&stats->rx_packets), ++ &session->stats.rx_packets); ++ atomic_long_add(atomic_long_read(&stats->rx_bytes), ++ &session->stats.rx_bytes); ++ atomic_long_add(atomic_long_read(&stats->tx_packets), ++ &session->stats.tx_packets); ++ atomic_long_add(atomic_long_read(&stats->tx_bytes), ++ &session->stats.tx_bytes); ++} ++EXPORT_SYMBOL_GPL(l2tp_stats_update); ++ ++ + /***************************************************************************** + * Receive data handling + *****************************************************************************/ +--- a/net/l2tp/l2tp_core.h ++++ b/net/l2tp/l2tp_core.h +@@ -232,6 +232,9 @@ struct l2tp_session *l2tp_session_get_nt + struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net, + const char *ifname); + ++void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session, ++ struct l2tp_stats *stats); ++ + /* Tunnel and session lifetime management. + * Creation of a new instance is a two-step process: create, then register. + * Destruction is triggered using the *_delete functions, and completes asynchronously. diff --git a/6.6/target/linux/qualcommax/patches-6.6/0603-3-qca-nss-clients-add-PPTP-support.patch b/6.6/target/linux/qualcommax/patches-6.6/0603-3-qca-nss-clients-add-PPTP-support.patch new file mode 100644 index 000000000..5fb9917bc --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0603-3-qca-nss-clients-add-PPTP-support.patch @@ -0,0 +1,478 @@ +--- a/include/linux/if_pppox.h ++++ b/include/linux/if_pppox.h +@@ -36,6 +36,7 @@ struct pptp_opt { + u32 ack_sent, ack_recv; + u32 seq_sent, seq_recv; + int ppp_flags; ++ bool pptp_offload_mode; + }; + #include + +@@ -100,8 +101,40 @@ struct pppoe_channel_ops { + int (*get_addressing)(struct ppp_channel *, struct pppoe_opt *); + }; + ++/* PPTP client callback */ ++typedef int (*pptp_gre_seq_offload_callback_t)(struct sk_buff *skb, ++ struct net_device *pptp_dev); ++ + /* Return PPPoE channel specific addressing information */ + extern int pppoe_channel_addressing_get(struct ppp_channel *chan, + struct pppoe_opt *addressing); + ++/* Lookup PPTP session info and return PPTP session using sip, dip and local call id */ ++extern int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id, ++ __be32 daddr, __be32 saddr); ++ ++/* Lookup PPTP session info and return PPTP session using dip and peer call id */ ++extern int pptp_session_find(struct pptp_opt *opt, __be16 peer_call_id, ++ __be32 peer_ip_addr); ++ ++/* Return PPTP session information given the channel */ ++extern void pptp_channel_addressing_get(struct pptp_opt *opt, ++ struct ppp_channel *chan); ++ ++/* Enable the PPTP session offload flag */ ++extern int pptp_session_enable_offload_mode(__be16 peer_call_id, ++ __be32 peer_ip_addr); ++ ++/* Disable the PPTP session offload flag */ ++extern int pptp_session_disable_offload_mode(__be16 peer_call_id, ++ __be32 peer_ip_addr); ++ ++/* Register the PPTP GRE packets sequence number offload callback */ ++extern int ++pptp_register_gre_seq_offload_callback(pptp_gre_seq_offload_callback_t ++ pptp_client_cb); ++ ++/* Unregister the PPTP GRE packets sequence number offload callback */ ++extern void pptp_unregister_gre_seq_offload_callback(void); ++ + #endif /* !(__LINUX_IF_PPPOX_H) */ +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -2973,6 +2973,20 @@ char *ppp_dev_name(struct ppp_channel *c + return name; + } + ++/* Return the PPP net device index */ ++int ppp_dev_index(struct ppp_channel *chan) ++{ ++ struct channel *pch = chan->ppp; ++ int ifindex = 0; ++ ++ if (pch) { ++ read_lock_bh(&pch->upl); ++ if (pch->ppp && pch->ppp->dev) ++ ifindex = pch->ppp->dev->ifindex; ++ read_unlock_bh(&pch->upl); ++ } ++ return ifindex; ++} + + /* + * Disconnect a channel from the generic layer. +@@ -3681,6 +3695,28 @@ void ppp_update_stats(struct net_device + ppp_recv_unlock(ppp); + } + ++/* Returns true if Compression is enabled on PPP device ++ */ ++bool ppp_is_cp_enabled(struct net_device *dev) ++{ ++ struct ppp *ppp; ++ bool flag = false; ++ ++ if (!dev) ++ return false; ++ ++ if (dev->type != ARPHRD_PPP) ++ return false; ++ ++ ppp = netdev_priv(dev); ++ ppp_lock(ppp); ++ flag = !!(ppp->xstate & SC_COMP_RUN) || !!(ppp->rstate & SC_DECOMP_RUN); ++ ppp_unlock(ppp); ++ ++ return flag; ++} ++EXPORT_SYMBOL(ppp_is_cp_enabled); ++ + /* Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 if + * the device is not PPP. + */ +@@ -3872,6 +3908,7 @@ EXPORT_SYMBOL(ppp_unregister_channel); + EXPORT_SYMBOL(ppp_channel_index); + EXPORT_SYMBOL(ppp_unit_number); + EXPORT_SYMBOL(ppp_dev_name); ++EXPORT_SYMBOL(ppp_dev_index); + EXPORT_SYMBOL(ppp_input); + EXPORT_SYMBOL(ppp_input_error); + EXPORT_SYMBOL(ppp_output_wakeup); +--- a/include/linux/ppp_channel.h ++++ b/include/linux/ppp_channel.h +@@ -84,6 +84,9 @@ extern void ppp_unregister_channel(struc + /* Get the channel number for a channel */ + extern int ppp_channel_index(struct ppp_channel *); + ++/* Get the device index associated with a channel, or 0, if none */ ++extern int ppp_dev_index(struct ppp_channel *); ++ + /* Get the unit number associated with a channel, or -1 if none */ + extern int ppp_unit_number(struct ppp_channel *); + +@@ -116,6 +119,7 @@ extern int ppp_hold_channels(struct net_ + /* Test if ppp xmit lock is locked */ + extern bool ppp_is_xmit_locked(struct net_device *dev); + ++bool ppp_is_cp_enabled(struct net_device *dev); + /* Test if the ppp device is a multi-link ppp device */ + extern int ppp_is_multilink(struct net_device *dev); + +--- a/drivers/net/ppp/pptp.c ++++ b/drivers/net/ppp/pptp.c +@@ -50,6 +50,8 @@ static struct proto pptp_sk_proto __read + static const struct ppp_channel_ops pptp_chan_ops; + static const struct proto_ops pptp_ops; + ++static pptp_gre_seq_offload_callback_t __rcu pptp_gre_offload_xmit_cb; ++ + static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr) + { + struct pppox_sock *sock; +@@ -91,6 +93,79 @@ static int lookup_chan_dst(u16 call_id, + return i < MAX_CALLID; + } + ++/* Search a pptp session based on local call id, local and remote ip address */ ++static int lookup_session_src(struct pptp_opt *opt, u16 call_id, __be32 daddr, __be32 saddr) ++{ ++ struct pppox_sock *sock; ++ int i = 1; ++ ++ rcu_read_lock(); ++ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) { ++ sock = rcu_dereference(callid_sock[i]); ++ if (!sock) ++ continue; ++ ++ if (sock->proto.pptp.src_addr.call_id == call_id && ++ sock->proto.pptp.dst_addr.sin_addr.s_addr == daddr && ++ sock->proto.pptp.src_addr.sin_addr.s_addr == saddr) { ++ sock_hold(sk_pppox(sock)); ++ memcpy(opt, &sock->proto.pptp, sizeof(struct pptp_opt)); ++ sock_put(sk_pppox(sock)); ++ rcu_read_unlock(); ++ return 0; ++ } ++ } ++ rcu_read_unlock(); ++ return -EINVAL; ++} ++ ++/* Search a pptp session based on peer call id and peer ip address */ ++static int lookup_session_dst(struct pptp_opt *opt, u16 call_id, __be32 d_addr) ++{ ++ struct pppox_sock *sock; ++ int i = 1; ++ ++ rcu_read_lock(); ++ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) { ++ sock = rcu_dereference(callid_sock[i]); ++ if (!sock) ++ continue; ++ ++ if (sock->proto.pptp.dst_addr.call_id == call_id && ++ sock->proto.pptp.dst_addr.sin_addr.s_addr == d_addr) { ++ sock_hold(sk_pppox(sock)); ++ memcpy(opt, &sock->proto.pptp, sizeof(struct pptp_opt)); ++ sock_put(sk_pppox(sock)); ++ rcu_read_unlock(); ++ return 0; ++ } ++ } ++ rcu_read_unlock(); ++ return -EINVAL; ++} ++ ++/* If offload mode set then this function sends all packets to ++ * offload module instead of network stack ++ */ ++static int pptp_client_skb_xmit(struct sk_buff *skb, ++ struct net_device *pptp_dev) ++{ ++ pptp_gre_seq_offload_callback_t pptp_gre_offload_cb_f; ++ int ret; ++ ++ rcu_read_lock(); ++ pptp_gre_offload_cb_f = rcu_dereference(pptp_gre_offload_xmit_cb); ++ ++ if (!pptp_gre_offload_cb_f) { ++ rcu_read_unlock(); ++ return -1; ++ } ++ ++ ret = pptp_gre_offload_cb_f(skb, pptp_dev); ++ rcu_read_unlock(); ++ return ret; ++} ++ + static int add_chan(struct pppox_sock *sock, + struct pptp_addr *sa) + { +@@ -136,7 +211,7 @@ static struct rtable *pptp_route_output( + struct net *net; + + net = sock_net(sk); +- flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, 0, ++ flowi4_init_output(fl4, 0, sk->sk_mark, 0, + RT_SCOPE_UNIVERSE, IPPROTO_GRE, 0, + po->proto.pptp.dst_addr.sin_addr.s_addr, + po->proto.pptp.src_addr.sin_addr.s_addr, +@@ -163,8 +238,11 @@ static int pptp_xmit(struct ppp_channel + + struct rtable *rt; + struct net_device *tdev; ++ struct net_device *pptp_dev; + struct iphdr *iph; + int max_headroom; ++ int pptp_ifindex; ++ int ret; + + if (sk_pppox(po)->sk_state & PPPOX_DEAD) + goto tx_error; +@@ -258,7 +336,32 @@ static int pptp_xmit(struct ppp_channel + ip_select_ident(net, skb, NULL); + ip_send_check(iph); + +- ip_local_out(net, skb->sk, skb); ++ pptp_ifindex = ppp_dev_index(chan); ++ ++ /* set incoming interface as the ppp interface */ ++ if (skb->skb_iif) ++ skb->skb_iif = pptp_ifindex; ++ ++ /* If the PPTP GRE seq number offload module is not enabled yet ++ * then sends all PPTP GRE packets through linux network stack ++ */ ++ if (!opt->pptp_offload_mode) { ++ ip_local_out(net, skb->sk, skb); ++ return 1; ++ } ++ ++ pptp_dev = dev_get_by_index(&init_net, pptp_ifindex); ++ if (!pptp_dev) ++ goto tx_error; ++ ++ /* If PPTP offload module is enabled then forward all PPTP GRE ++ * packets to PPTP GRE offload module ++ */ ++ ret = pptp_client_skb_xmit(skb, pptp_dev); ++ dev_put(pptp_dev); ++ if (ret < 0) ++ goto tx_error; ++ + return 1; + + tx_error: +@@ -314,6 +417,13 @@ static int pptp_rcv_core(struct sock *sk + goto drop; + + payload = skb->data + headersize; ++ ++ /* If offload is enabled, we expect the offload module ++ * to handle PPTP GRE sequence number checks ++ */ ++ if (opt->pptp_offload_mode) ++ goto allow_packet; ++ + /* check for expected sequence number */ + if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) { + if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) && +@@ -371,6 +481,7 @@ static int pptp_rcv(struct sk_buff *skb) + if (po) { + skb_dst_drop(skb); + nf_reset_ct(skb); ++ skb->skb_iif = ppp_dev_index(&po->chan); + return sk_receive_skb(sk_pppox(po), skb, 0); + } + drop: +@@ -473,7 +584,7 @@ static int pptp_connect(struct socket *s + + opt->dst_addr = sp->sa_addr.pptp; + sk->sk_state |= PPPOX_CONNECTED; +- ++ opt->pptp_offload_mode = false; + end: + release_sock(sk); + return error; +@@ -603,9 +714,169 @@ static int pptp_ppp_ioctl(struct ppp_cha + return err; + } + ++/* pptp_channel_addressing_get() ++ * Return PPTP channel specific addressing information. ++ */ ++void pptp_channel_addressing_get(struct pptp_opt *opt, struct ppp_channel *chan) ++{ ++ struct sock *sk; ++ struct pppox_sock *po; ++ ++ if (!opt) ++ return; ++ ++ sk = (struct sock *)chan->private; ++ if (!sk) ++ return; ++ ++ sock_hold(sk); ++ ++ /* This is very unlikely, but check the socket is connected state */ ++ if (unlikely(sock_flag(sk, SOCK_DEAD) || ++ !(sk->sk_state & PPPOX_CONNECTED))) { ++ sock_put(sk); ++ return; ++ } ++ ++ po = pppox_sk(sk); ++ memcpy(opt, &po->proto.pptp, sizeof(struct pptp_opt)); ++ sock_put(sk); ++} ++EXPORT_SYMBOL(pptp_channel_addressing_get); ++ ++/* pptp_session_find() ++ * Search and return a PPTP session info based on peer callid and IP ++ * address. The function accepts the parameters in network byte order. ++ */ ++int pptp_session_find(struct pptp_opt *opt, __be16 peer_call_id, ++ __be32 peer_ip_addr) ++{ ++ if (!opt) ++ return -EINVAL; ++ ++ return lookup_session_dst(opt, ntohs(peer_call_id), peer_ip_addr); ++} ++EXPORT_SYMBOL(pptp_session_find); ++ ++/* pptp_session_find_by_src_callid() ++ * Search and return a PPTP session info based on src callid and IP ++ * address. The function accepts the parameters in network byte order. ++ */ ++int pptp_session_find_by_src_callid(struct pptp_opt *opt, __be16 src_call_id, ++ __be32 daddr, __be32 saddr) ++{ ++ if (!opt) ++ return -EINVAL; ++ ++ return lookup_session_src(opt, ntohs(src_call_id), daddr, saddr); ++} ++EXPORT_SYMBOL(pptp_session_find_by_src_callid); ++ ++ /* Function to change the offload mode true/false for a PPTP session */ ++static int pptp_set_offload_mode(bool accel_mode, ++ __be16 peer_call_id, __be32 peer_ip_addr) ++{ ++ struct pppox_sock *sock; ++ int i = 1; ++ ++ rcu_read_lock(); ++ for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) { ++ sock = rcu_dereference(callid_sock[i]); ++ if (!sock) ++ continue; ++ ++ if (sock->proto.pptp.dst_addr.call_id == peer_call_id && ++ sock->proto.pptp.dst_addr.sin_addr.s_addr == peer_ip_addr) { ++ sock_hold(sk_pppox(sock)); ++ sock->proto.pptp.pptp_offload_mode = accel_mode; ++ sock_put(sk_pppox(sock)); ++ rcu_read_unlock(); ++ return 0; ++ } ++ } ++ rcu_read_unlock(); ++ return -EINVAL; ++} ++ ++/* Enable the PPTP session offload flag */ ++int pptp_session_enable_offload_mode(__be16 peer_call_id, __be32 peer_ip_addr) ++{ ++ return pptp_set_offload_mode(true, peer_call_id, peer_ip_addr); ++} ++EXPORT_SYMBOL(pptp_session_enable_offload_mode); ++ ++/* Disable the PPTP session offload flag */ ++int pptp_session_disable_offload_mode(__be16 peer_call_id, __be32 peer_ip_addr) ++{ ++ return pptp_set_offload_mode(false, peer_call_id, peer_ip_addr); ++} ++EXPORT_SYMBOL(pptp_session_disable_offload_mode); ++ ++/* Register the offload callback function on behalf of the module which ++ * will own the sequence and acknowledgment number updates for all ++ * PPTP GRE packets. All PPTP GRE packets are then transmitted to this ++ * module after encapsulation in order to ensure the correct seq/ack ++ * fields are set in the packets before transmission. This is required ++ * when PPTP flows are offloaded to acceleration engines, in-order to ++ * ensure consistency in sequence and ack numbers between PPTP control ++ * (PPP LCP) and data packets ++ */ ++int pptp_register_gre_seq_offload_callback(pptp_gre_seq_offload_callback_t ++ pptp_gre_offload_cb) ++{ ++ pptp_gre_seq_offload_callback_t pptp_gre_offload_cb_f; ++ ++ rcu_read_lock(); ++ pptp_gre_offload_cb_f = rcu_dereference(pptp_gre_offload_xmit_cb); ++ ++ if (pptp_gre_offload_cb_f) { ++ rcu_read_unlock(); ++ return -1; ++ } ++ ++ rcu_assign_pointer(pptp_gre_offload_xmit_cb, pptp_gre_offload_cb); ++ rcu_read_unlock(); ++ return 0; ++} ++EXPORT_SYMBOL(pptp_register_gre_seq_offload_callback); ++ ++/* Unregister the PPTP GRE packets sequence number offload callback */ ++void pptp_unregister_gre_seq_offload_callback(void) ++{ ++ rcu_assign_pointer(pptp_gre_offload_xmit_cb, NULL); ++} ++EXPORT_SYMBOL(pptp_unregister_gre_seq_offload_callback); ++ ++/* pptp_hold_chan() */ ++static void pptp_hold_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_hold(sk); ++} ++ ++/* pptp_release_chan() */ ++static void pptp_release_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_put(sk); ++} ++ ++/* pptp_get_channel_protocol() ++ * Return the protocol type of the PPTP over PPP protocol ++ */ ++static int pptp_get_channel_protocol(struct ppp_channel *chan) ++{ ++ return PX_PROTO_PPTP; ++} ++ + static const struct ppp_channel_ops pptp_chan_ops = { + .start_xmit = pptp_xmit, + .ioctl = pptp_ppp_ioctl, ++ .get_channel_protocol = pptp_get_channel_protocol, ++ .hold = pptp_hold_chan, ++ .release = pptp_release_chan, + }; + + static struct proto pptp_sk_proto __read_mostly = { diff --git a/6.6/target/linux/qualcommax/patches-6.6/0603-4-qca-nss-clients-add-iptunnel-support.patch b/6.6/target/linux/qualcommax/patches-6.6/0603-4-qca-nss-clients-add-iptunnel-support.patch new file mode 100644 index 000000000..c9fc33686 --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0603-4-qca-nss-clients-add-iptunnel-support.patch @@ -0,0 +1,77 @@ +--- a/include/net/ip6_tunnel.h ++++ b/include/net/ip6_tunnel.h +@@ -36,6 +36,7 @@ struct __ip6_tnl_parm { + __u8 proto; /* tunnel protocol */ + __u8 encap_limit; /* encapsulation limit for tunnel */ + __u8 hop_limit; /* hop limit for tunnel */ ++ __u8 draft03; /* FMR using draft03 of map-e - QCA NSS Clients Support */ + bool collect_md; + __be32 flowinfo; /* traffic class and flowlabel for tunnel */ + __u32 flags; /* tunnel flags */ +--- a/include/net/ip_tunnels.h ++++ b/include/net/ip_tunnels.h +@@ -558,4 +558,9 @@ static inline void ip_tunnel_info_opts_s + + #endif /* CONFIG_INET */ + ++/* QCA NSS Clients Support - Start */ ++void ipip6_update_offload_stats(struct net_device *dev, void *ptr); ++void ip6_update_offload_stats(struct net_device *dev, void *ptr); ++/* QCA NSS Clients Support - End */ ++ + #endif /* __NET_IP_TUNNELS_H */ +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -2411,6 +2411,26 @@ nla_put_failure: + return -EMSGSIZE; + } + ++/* QCA NSS Client Support - Start */ ++/* ++ * Update offload stats ++ */ ++void ip6_update_offload_stats(struct net_device *dev, void *ptr) ++{ ++ struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0); ++ const struct pcpu_sw_netstats *offload_stats = ++ (struct pcpu_sw_netstats *)ptr; ++ ++ u64_stats_update_begin(&tstats->syncp); ++ u64_stats_add(&tstats->tx_packets, u64_stats_read(&offload_stats->tx_packets)); ++ u64_stats_add(&tstats->tx_bytes, u64_stats_read(&offload_stats->tx_bytes)); ++ u64_stats_add(&tstats->rx_packets, u64_stats_read(&offload_stats->rx_packets)); ++ u64_stats_add(&tstats->rx_bytes, u64_stats_read(&offload_stats->rx_bytes)); ++ u64_stats_update_end(&tstats->syncp); ++} ++EXPORT_SYMBOL(ip6_update_offload_stats); ++/* QCA NSS Client Support - End */ ++ + struct net *ip6_tnl_get_link_net(const struct net_device *dev) + { + struct ip6_tnl *tunnel = netdev_priv(dev); +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -1733,6 +1733,23 @@ nla_put_failure: + return -EMSGSIZE; + } + ++/* QCA NSS Clients Support - Start */ ++void ipip6_update_offload_stats(struct net_device *dev, void *ptr) ++{ ++ struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0); ++ const struct pcpu_sw_netstats *offload_stats = ++ (struct pcpu_sw_netstats *)ptr; ++ ++ u64_stats_update_begin(&tstats->syncp); ++ u64_stats_add(&tstats->tx_packets, u64_stats_read(&offload_stats->tx_packets)); ++ u64_stats_add(&tstats->tx_bytes, u64_stats_read(&offload_stats->tx_bytes)); ++ u64_stats_add(&tstats->rx_packets, u64_stats_read(&offload_stats->rx_packets)); ++ u64_stats_add(&tstats->rx_bytes, u64_stats_read(&offload_stats->rx_bytes)); ++ u64_stats_update_end(&tstats->syncp); ++} ++EXPORT_SYMBOL(ipip6_update_offload_stats); ++/* QCA NSS Clients Support - End */ ++ + static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, + [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, diff --git a/6.6/target/linux/qualcommax/patches-6.6/0603-5-qca-nss-clients-add-vxlan-support.patch b/6.6/target/linux/qualcommax/patches-6.6/0603-5-qca-nss-clients-add-vxlan-support.patch new file mode 100644 index 000000000..7d05fd1af --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0603-5-qca-nss-clients-add-vxlan-support.patch @@ -0,0 +1,103 @@ +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -29,6 +29,20 @@ + #include + #include + ++ATOMIC_NOTIFIER_HEAD(vxlan_fdb_notifier_list); ++ ++void vxlan_fdb_register_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_register(&vxlan_fdb_notifier_list, nb); ++} ++EXPORT_SYMBOL(vxlan_fdb_register_notify); ++ ++void vxlan_fdb_unregister_notify(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_unregister(&vxlan_fdb_notifier_list, nb); ++} ++EXPORT_SYMBOL(vxlan_fdb_unregister_notify); ++ + #if IS_ENABLED(CONFIG_IPV6) + #include + #include +@@ -260,6 +274,7 @@ static void __vxlan_fdb_notify(struct vx + { + struct net *net = dev_net(vxlan->dev); + struct sk_buff *skb; ++ struct vxlan_fdb_event vfe; + int err = -ENOBUFS; + + skb = nlmsg_new(vxlan_nlmsg_size(), GFP_ATOMIC); +@@ -275,6 +290,10 @@ static void __vxlan_fdb_notify(struct vx + } + + rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); ++ vfe.dev = vxlan->dev; ++ vfe.rdst = rd; ++ ether_addr_copy(vfe.eth_addr, fdb->eth_addr); ++ atomic_notifier_call_chain(&vxlan_fdb_notifier_list, type, (void *)&vfe); + return; + errout: + if (err < 0) +@@ -441,6 +460,18 @@ static struct vxlan_fdb *vxlan_find_mac( + return f; + } + ++/* Find and update age of fdb entry corresponding to MAC. */ ++void vxlan_fdb_update_mac(struct vxlan_dev *vxlan, const u8 *mac, uint32_t vni) ++{ ++ u32 hash_index; ++ ++ hash_index = fdb_head_index(vxlan, mac, vni); ++ spin_lock_bh(&vxlan->hash_lock[hash_index]); ++ vxlan_find_mac(vxlan, mac, vni); ++ spin_unlock_bh(&vxlan->hash_lock[hash_index]); ++} ++EXPORT_SYMBOL(vxlan_fdb_update_mac); ++ + /* caller should hold vxlan->hash_lock */ + static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f, + union vxlan_addr *ip, __be16 port, +@@ -2581,6 +2612,9 @@ void vxlan_xmit_one(struct sk_buff *skb, + goto out_unlock; + } + ++ /* Reset the skb_iif to Tunnels interface index */ ++ skb->skb_iif = dev->ifindex; ++ + tos = ip_tunnel_ecn_encap(tos, old_iph, skb); + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), +@@ -2652,6 +2686,9 @@ void vxlan_xmit_one(struct sk_buff *skb, + if (err < 0) + goto tx_error; + ++ /* Reset the skb_iif to Tunnels interface index */ ++ skb->skb_iif = dev->ifindex; ++ + udp_tunnel6_xmit_skb(ndst, sock6->sock->sk, skb, dev, + &local_ip.sin6.sin6_addr, + &dst->sin6.sin6_addr, tos, ttl, +--- a/include/net/vxlan.h ++++ b/include/net/vxlan.h +@@ -352,6 +352,19 @@ struct vxlan_dev { + VXLAN_F_VNIFILTER | \ + VXLAN_F_LOCALBYPASS) + ++/* ++ * Application data for fdb notifier event ++ */ ++struct vxlan_fdb_event { ++ struct net_device *dev; ++ struct vxlan_rdst *rdst; ++ u8 eth_addr[ETH_ALEN]; ++}; ++ ++extern void vxlan_fdb_register_notify(struct notifier_block *nb); ++extern void vxlan_fdb_unregister_notify(struct notifier_block *nb); ++extern void vxlan_fdb_update_mac(struct vxlan_dev *vxlan, const u8 *mac, uint32_t vni); ++ + struct net_device *vxlan_dev_create(struct net *net, const char *name, + u8 name_assign_type, struct vxlan_config *conf); + diff --git a/6.6/target/linux/qualcommax/patches-6.6/0603-6-qca-nss-clients-add-l2tp-offloading-support.patch b/6.6/target/linux/qualcommax/patches-6.6/0603-6-qca-nss-clients-add-l2tp-offloading-support.patch new file mode 100644 index 000000000..4032eb3c2 --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0603-6-qca-nss-clients-add-l2tp-offloading-support.patch @@ -0,0 +1,368 @@ +--- a/include/linux/ppp_channel.h ++++ b/include/linux/ppp_channel.h +@@ -61,6 +61,51 @@ struct ppp_channel { + }; + + #ifdef __KERNEL__ ++/* Call this to obtain the underlying protocol of the PPP channel, ++ * e.g. PX_PROTO_OE ++ */ ++extern int ppp_channel_get_protocol(struct ppp_channel *); ++ ++/* Call this to hold a channel */ ++extern bool ppp_channel_hold(struct ppp_channel *); ++ ++/* Call this to release a hold you have upon a channel */ ++extern void ppp_channel_release(struct ppp_channel *); ++ ++/* Release hold on PPP channels */ ++extern void ppp_release_channels(struct ppp_channel *channels[], ++ unsigned int chan_sz); ++ ++/* Test if ppp xmit lock is locked */ ++extern bool ppp_is_xmit_locked(struct net_device *dev); ++ ++/* Call this get protocol version */ ++extern int ppp_channel_get_proto_version(struct ppp_channel *); ++ ++/* Get the device index associated with a channel, or 0, if none */ ++extern int ppp_dev_index(struct ppp_channel *); ++ ++/* Hold PPP channels for the PPP device */ ++extern int ppp_hold_channels(struct net_device *dev, ++ struct ppp_channel *channels[], ++ unsigned int chan_sz); ++extern int __ppp_hold_channels(struct net_device *dev, ++ struct ppp_channel *channels[], ++ unsigned int chan_sz); ++ ++/* Test if the ppp device is a multi-link ppp device */ ++extern int ppp_is_multilink(struct net_device *dev); ++extern int __ppp_is_multilink(struct net_device *dev); ++ ++/* Update statistics of the PPP net_device by incrementing related ++ * statistics field value with corresponding parameter ++ */ ++extern void ppp_update_stats(struct net_device *dev, unsigned long rx_packets, ++ unsigned long rx_bytes, unsigned long tx_packets, ++ unsigned long tx_bytes, unsigned long rx_errors, ++ unsigned long tx_errors, unsigned long rx_dropped, ++ unsigned long tx_dropped); ++ + /* Called by the channel when it can send some more data. */ + extern void ppp_output_wakeup(struct ppp_channel *); + +@@ -148,5 +193,17 @@ extern void ppp_update_stats(struct net_ + * that ppp_unregister_channel returns. + */ + ++/* QCA NSS Clients Support - Start */ ++/* PPP channel connection event types */ ++#define PPP_CHANNEL_DISCONNECT 0 ++#define PPP_CHANNEL_CONNECT 1 ++ ++/* Register the PPP channel connect notifier */ ++extern void ppp_channel_connection_register_notify(struct notifier_block *nb); ++ ++/* Unregister the PPP channel connect notifier */ ++extern void ppp_channel_connection_unregister_notify(struct notifier_block *nb); ++/* QCA NSS Clients Support - End */ ++ + #endif /* __KERNEL__ */ + #endif +--- a/include/linux/if_pppol2tp.h ++++ b/include/linux/if_pppol2tp.h +@@ -12,4 +12,30 @@ + #include + #include + ++/* QCA NSS ECM support - Start */ ++/* ++ * Holds L2TP channel info ++ */ ++struct pppol2tp_common_addr { ++ int tunnel_version; /* v2 or v3 */ ++ __u32 local_tunnel_id, remote_tunnel_id; /* tunnel id */ ++ __u32 local_session_id, remote_session_id; /* session id */ ++ struct sockaddr_in local_addr, remote_addr; /* ip address and port */ ++}; ++ ++/* ++ * L2TP channel operations ++ */ ++struct pppol2tp_channel_ops { ++ struct ppp_channel_ops ops; /* ppp channel ops */ ++}; ++ ++/* ++ * exported function which calls pppol2tp channel's get addressing ++ * function ++ */ ++extern int pppol2tp_channel_addressing_get(struct ppp_channel *, ++ struct pppol2tp_common_addr *); ++/* QCA NSS ECM support - End */ ++ + #endif +--- a/net/l2tp/l2tp_ppp.c ++++ b/net/l2tp/l2tp_ppp.c +@@ -123,9 +123,17 @@ struct pppol2tp_session { + }; + + static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb); +- +-static const struct ppp_channel_ops pppol2tp_chan_ops = { +- .start_xmit = pppol2tp_xmit, ++static int pppol2tp_get_channel_protocol(struct ppp_channel *); ++static int pppol2tp_get_channel_protocol_ver(struct ppp_channel *); ++static void pppol2tp_hold_chan(struct ppp_channel *); ++static void pppol2tp_release_chan(struct ppp_channel *); ++ ++static const struct pppol2tp_channel_ops pppol2tp_chan_ops = { ++ .ops.start_xmit = pppol2tp_xmit, ++ .ops.get_channel_protocol = pppol2tp_get_channel_protocol, ++ .ops.get_channel_protocol_ver = pppol2tp_get_channel_protocol_ver, ++ .ops.hold = pppol2tp_hold_chan, ++ .ops.release = pppol2tp_release_chan, + }; + + static const struct proto_ops pppol2tp_ops; +@@ -373,6 +381,13 @@ static int pppol2tp_xmit(struct ppp_chan + skb->data[0] = PPP_ALLSTATIONS; + skb->data[1] = PPP_UI; + ++ /* QCA NSS ECM support - start */ ++ /* set incoming interface as the ppp interface */ ++ if ((skb->protocol == htons(ETH_P_IP)) || ++ (skb->protocol == htons(ETH_P_IPV6))) ++ skb->skb_iif = ppp_dev_index(chan); ++ /* QCA NSS ECM support - End */ ++ + local_bh_disable(); + l2tp_xmit_skb(session, skb); + local_bh_enable(); +@@ -818,7 +833,7 @@ static int pppol2tp_connect(struct socke + po->chan.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ; + + po->chan.private = sk; +- po->chan.ops = &pppol2tp_chan_ops; ++ po->chan.ops = (struct ppp_channel_ops *)&pppol2tp_chan_ops.ops; + po->chan.mtu = pppol2tp_tunnel_mtu(tunnel); + + error = ppp_register_net_channel(sock_net(sk), &po->chan); +@@ -1732,6 +1747,109 @@ static void __exit pppol2tp_exit(void) + unregister_pernet_device(&pppol2tp_net_ops); + } + ++/* QCA NSS ECM support - Start */ ++/* pppol2tp_hold_chan() */ ++static void pppol2tp_hold_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_hold(sk); ++} ++ ++/* pppol2tp_release_chan() */ ++static void pppol2tp_release_chan(struct ppp_channel *chan) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ ++ sock_put(sk); ++} ++ ++/* pppol2tp_get_channel_protocol() ++ * Return the protocol type of the L2TP over PPP protocol ++ */ ++static int pppol2tp_get_channel_protocol(struct ppp_channel *chan) ++{ ++ return PX_PROTO_OL2TP; ++} ++ ++/* pppol2tp_get_channel_protocol_ver() ++ * Return the protocol version of the L2TP over PPP protocol ++ */ ++static int pppol2tp_get_channel_protocol_ver(struct ppp_channel *chan) ++{ ++ struct sock *sk; ++ struct l2tp_session *session; ++ struct l2tp_tunnel *tunnel; ++ int version = 0; ++ ++ if (chan && chan->private) ++ sk = (struct sock *)chan->private; ++ else ++ return -1; ++ ++ /* Get session and tunnel contexts from the socket */ ++ session = pppol2tp_sock_to_session(sk); ++ if (!session) ++ return -1; ++ ++ tunnel = session->tunnel; ++ if (!tunnel) { ++ sock_put(sk); ++ return -1; ++ } ++ ++ version = tunnel->version; ++ ++ sock_put(sk); ++ ++ return version; ++} ++ ++/* pppol2tp_get_addressing() */ ++static int pppol2tp_get_addressing(struct ppp_channel *chan, ++ struct pppol2tp_common_addr *addr) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ struct l2tp_session *session; ++ struct l2tp_tunnel *tunnel; ++ struct inet_sock *isk = NULL; ++ int err = -ENXIO; ++ ++ /* Get session and tunnel contexts from the socket */ ++ session = pppol2tp_sock_to_session(sk); ++ if (!session) ++ return err; ++ ++ tunnel = session->tunnel; ++ if (!tunnel) { ++ sock_put(sk); ++ return err; ++ } ++ isk = inet_sk(tunnel->sock); ++ ++ addr->local_tunnel_id = tunnel->tunnel_id; ++ addr->remote_tunnel_id = tunnel->peer_tunnel_id; ++ addr->local_session_id = session->session_id; ++ addr->remote_session_id = session->peer_session_id; ++ ++ addr->local_addr.sin_port = isk->inet_sport; ++ addr->remote_addr.sin_port = isk->inet_dport; ++ addr->local_addr.sin_addr.s_addr = isk->inet_saddr; ++ addr->remote_addr.sin_addr.s_addr = isk->inet_daddr; ++ ++ sock_put(sk); ++ return 0; ++} ++ ++/* pppol2tp_channel_addressing_get() */ ++int pppol2tp_channel_addressing_get(struct ppp_channel *chan, ++ struct pppol2tp_common_addr *addr) ++{ ++ return pppol2tp_get_addressing(chan, addr); ++} ++EXPORT_SYMBOL(pppol2tp_channel_addressing_get); ++/* QCA NSS ECM support - End */ ++ + module_init(pppol2tp_init); + module_exit(pppol2tp_exit); + +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -3743,6 +3743,32 @@ int ppp_is_multilink(struct net_device * + } + EXPORT_SYMBOL(ppp_is_multilink); + ++/* __ppp_is_multilink() ++ * Returns >0 if the device is a multilink PPP netdevice, 0 if not or < 0 ++ * if the device is not PPP. Caller should acquire ppp_lock before calling ++ * this function ++ */ ++int __ppp_is_multilink(struct net_device *dev) ++{ ++ struct ppp *ppp; ++ unsigned int flags; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ flags = ppp->flags; ++ ++ if (flags & SC_MULTILINK) ++ return 1; ++ ++ return 0; ++} ++EXPORT_SYMBOL(__ppp_is_multilink); ++ + /* ppp_channel_get_protocol() + * Call this to obtain the underlying protocol of the PPP channel, + * e.g. PX_PROTO_OE +@@ -3881,6 +3907,59 @@ int ppp_hold_channels(struct net_device + } + EXPORT_SYMBOL(ppp_hold_channels); + ++/* __ppp_hold_channels() ++ * Returns the PPP channels of the PPP device, storing each one into ++ * channels[]. ++ * ++ * channels[] has chan_sz elements. ++ * This function returns the number of channels stored, up to chan_sz. ++ * It will return < 0 if the device is not PPP. ++ * ++ * You MUST release the channels using ppp_release_channels(). ++ */ ++int __ppp_hold_channels(struct net_device *dev, struct ppp_channel *channels[], ++ unsigned int chan_sz) ++{ ++ struct ppp *ppp; ++ int c; ++ struct channel *pch; ++ ++ if (!dev) ++ return -1; ++ ++ if (dev->type != ARPHRD_PPP) ++ return -1; ++ ++ ppp = netdev_priv(dev); ++ ++ c = 0; ++ list_for_each_entry(pch, &ppp->channels, clist) { ++ struct ppp_channel *chan; ++ ++ if (!pch->chan) { ++ /* Channel is going / gone away */ ++ continue; ++ } ++ ++ if (c == chan_sz) { ++ /* No space to record channel */ ++ return c; ++ } ++ ++ /* Hold the channel, if supported */ ++ chan = pch->chan; ++ if (!chan->ops->hold) ++ continue; ++ ++ chan->ops->hold(chan); ++ ++ /* Record the channel */ ++ channels[c++] = chan; ++ } ++ return c; ++} ++EXPORT_SYMBOL(__ppp_hold_channels); ++ + /* ppp_release_channels() + * Releases channels + */ +--- a/net/l2tp/l2tp_core.h ++++ b/net/l2tp/l2tp_core.h +@@ -235,6 +235,9 @@ struct l2tp_session *l2tp_session_get_by + void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session, + struct l2tp_stats *stats); + ++void l2tp_stats_update(struct l2tp_tunnel *tunnel, struct l2tp_session *session, ++ struct l2tp_stats *stats); ++ + /* Tunnel and session lifetime management. + * Creation of a new instance is a two-step process: create, then register. + * Destruction is triggered using the *_delete functions, and completes asynchronously. diff --git a/6.6/target/linux/qualcommax/patches-6.6/0603-7-qca-nss-clients-iptunnel-lock-this-cpu.patch b/6.6/target/linux/qualcommax/patches-6.6/0603-7-qca-nss-clients-iptunnel-lock-this-cpu.patch new file mode 100644 index 000000000..e4ed49ea4 --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0603-7-qca-nss-clients-iptunnel-lock-this-cpu.patch @@ -0,0 +1,22 @@ +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -2417,7 +2417,7 @@ nla_put_failure: + */ + void ip6_update_offload_stats(struct net_device *dev, void *ptr) + { +- struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0); ++ struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); + const struct pcpu_sw_netstats *offload_stats = + (struct pcpu_sw_netstats *)ptr; + +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -1736,7 +1736,7 @@ nla_put_failure: + /* QCA NSS Clients Support - Start */ + void ipip6_update_offload_stats(struct net_device *dev, void *ptr) + { +- struct pcpu_sw_netstats *tstats = per_cpu_ptr(dev->tstats, 0); ++ struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); + const struct pcpu_sw_netstats *offload_stats = + (struct pcpu_sw_netstats *)ptr; + diff --git a/6.6/target/linux/qualcommax/patches-6.6/0603-8-qca-nss-clients-add-tls-mgr-support.patch b/6.6/target/linux/qualcommax/patches-6.6/0603-8-qca-nss-clients-add-tls-mgr-support.patch new file mode 100644 index 000000000..0499e237f --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0603-8-qca-nss-clients-add-tls-mgr-support.patch @@ -0,0 +1,24 @@ +--- /dev/null ++++ b/include/uapi/linux/tlshdr.h +@@ -0,0 +1,21 @@ ++#ifndef _UAPI_LINUX_TLSHDR_H ++#define _UAPI_LINUX_TLSHDR_H ++ ++#include ++ ++struct tlshdr { ++ __u8 type; ++ __be16 version; ++ __be16 len; ++} __attribute__((packed)); ++ ++#define TLSHDR_REC_TYPE_CCS 20 /* TLS packet is change cipher specification */ ++#define TLSHDR_REC_TYPE_ALERT 21 /* TLS packet is Alert */ ++#define TLSHDR_REC_TYPE_HANDSHAKE 22 /* TLS packet is Handshake */ ++#define TLSHDR_REC_TYPE_DATA 23 /* TLS packet is Application data */ ++ ++#define TLSHDR_VERSION_1_1 0x0302 /* TLS Header Version(tls 1.1) */ ++#define TLSHDR_VERSION_1_2 0x0303 /* TLS Header Version(tls 1.2) */ ++#define TLSHDR_VERSION_1_3 0x0304 /* TLS Header Version(tls 1.3) */ ++ ++#endif /* _UAPI_LINUX_TLSHDR_H */ diff --git a/6.6/target/linux/qualcommax/patches-6.6/0604-1-qca-add-mcs-support.patch b/6.6/target/linux/qualcommax/patches-6.6/0604-1-qca-add-mcs-support.patch new file mode 100644 index 000000000..edf21700c --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0604-1-qca-add-mcs-support.patch @@ -0,0 +1,876 @@ +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -258,4 +258,17 @@ extern br_get_dst_hook_t __rcu *br_get_d + extern struct net_device *br_fdb_bridge_dev_get_and_hold(struct net_bridge *br); + /* QCA NSS bridge-mgr support - End */ + ++/* QCA qca-mcs support - Start */ ++typedef struct net_bridge_port *br_get_dst_hook_t(const struct net_bridge_port *src, ++ struct sk_buff **skb); ++extern br_get_dst_hook_t __rcu *br_get_dst_hook; ++ ++typedef int (br_multicast_handle_hook_t)(const struct net_bridge_port *src, ++ struct sk_buff *skb); ++extern br_multicast_handle_hook_t __rcu *br_multicast_handle_hook; ++ ++typedef void (br_notify_hook_t)(int group, int event, const void *ptr); ++extern br_notify_hook_t __rcu *br_notify_hook; ++/* QCA qca-mcs support - End */ ++ + #endif +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -239,6 +239,8 @@ static void fdb_notify(struct net_bridge + kfree_skb(skb); + goto errout; + } ++ ++ __br_notify(RTNLGRP_NEIGH, type, fdb); /* QCA qca-mcs support */ + rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); + return; + errout: +@@ -305,6 +307,7 @@ struct net_bridge_fdb_entry *br_fdb_find + { + return fdb_find_rcu(&br->fdb_hash_tbl, addr, vid); + } ++EXPORT_SYMBOL_GPL(br_fdb_find_rcu); /* QCA qca-mcs support */ + + /* When a static FDB entry is added, the mac address from the entry is + * added to the bridge private HW address list and all required ports +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -906,6 +906,7 @@ void br_manage_promisc(struct net_bridge + int nbp_backup_change(struct net_bridge_port *p, struct net_device *backup_dev); + + /* br_input.c */ ++int br_pass_frame_up(struct sk_buff *skb); /* QCA qca-mcs support */ + int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb); + rx_handler_func_t *br_get_rx_handler(const struct net_device *dev); + +@@ -2268,4 +2269,14 @@ struct nd_msg *br_is_nd_neigh_msg(struct + bool br_is_neigh_suppress_enabled(const struct net_bridge_port *p, u16 vid); + #define __br_get(__hook, __default, __args ...) \ + (__hook ? (__hook(__args)) : (__default)) /* QCA NSS ECM support */ ++ ++/* QCA qca-mcs support - Start */ ++static inline void __br_notify(int group, int type, const void *data) ++{ ++ br_notify_hook_t *notify_hook = rcu_dereference(br_notify_hook); ++ ++ if (notify_hook) ++ notify_hook(group, type, data); ++} ++/* QCA qca-mcs support - End */ + #endif +--- a/net/bridge/br_netlink.c ++++ b/net/bridge/br_netlink.c +@@ -656,6 +656,7 @@ void br_info_notify(int event, const str + kfree_skb(skb); + goto errout; + } ++ __br_notify(RTNLGRP_LINK, event, port); /* QCA qca-mcs support */ + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); + return; + errout: +--- a/net/bridge/br.c ++++ b/net/bridge/br.c +@@ -472,6 +472,12 @@ static void __exit br_deinit(void) + br_fdb_fini(); + } + ++/* QCA qca-mcs support - Start */ ++/* Hook for bridge event notifications */ ++br_notify_hook_t __rcu *br_notify_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_notify_hook); ++/* QCA qca-mcs support - End */ ++ + module_init(br_init) + module_exit(br_deinit) + MODULE_LICENSE("GPL"); +--- a/net/bridge/br_device.c ++++ b/net/bridge/br_device.c +@@ -83,6 +83,13 @@ netdev_tx_t br_dev_xmit(struct sk_buff * + if (is_broadcast_ether_addr(dest)) { + br_flood(br, skb, BR_PKT_BROADCAST, false, true, vid); + } else if (is_multicast_ether_addr(dest)) { ++ /* QCA qca-mcs support - Start */ ++ br_multicast_handle_hook_t *multicast_handle_hook = ++ rcu_dereference(br_multicast_handle_hook); ++ if (!__br_get(multicast_handle_hook, true, NULL, skb)) ++ goto out; ++ /* QCA qca-mcs support - End */ ++ + if (unlikely(netpoll_tx_running(dev))) { + br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid); + goto out; +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -30,7 +30,17 @@ br_netif_receive_skb(struct net *net, st + return netif_receive_skb(skb); + } + +-static int br_pass_frame_up(struct sk_buff *skb) ++/* QCA qca-mcs support - Start */ ++/* Hook for external Multicast handler */ ++br_multicast_handle_hook_t __rcu *br_multicast_handle_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_multicast_handle_hook); ++ ++/* Hook for external forwarding logic */ ++br_get_dst_hook_t __rcu *br_get_dst_hook __read_mostly; ++EXPORT_SYMBOL_GPL(br_get_dst_hook); ++/* QCA qca-mcs support - End */ ++ ++int br_pass_frame_up(struct sk_buff *skb) + { + struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev; + struct net_bridge *br = netdev_priv(brdev); +@@ -69,6 +79,7 @@ static int br_pass_frame_up(struct sk_bu + dev_net(indev), NULL, skb, indev, NULL, + br_netif_receive_skb); + } ++EXPORT_SYMBOL_GPL(br_pass_frame_up); /* QCA qca-mcs support */ + + /* note: already called with rcu_read_lock */ + int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb) +@@ -82,6 +93,11 @@ int br_handle_frame_finish(struct net *n + struct net_bridge_mcast *brmctx; + struct net_bridge_vlan *vlan; + struct net_bridge *br; ++ /* QCA qca-mcs support - Start */ ++ br_multicast_handle_hook_t *multicast_handle_hook; ++ struct net_bridge_port *pdst = NULL; ++ br_get_dst_hook_t *get_dst_hook = rcu_dereference(br_get_dst_hook); ++ /* QCA qca-mcs support - End */ + u16 vid = 0; + u8 state; + +@@ -175,6 +191,12 @@ int br_handle_frame_finish(struct net *n + + switch (pkt_type) { + case BR_PKT_MULTICAST: ++ /* QCA qca-mcs support - Start */ ++ multicast_handle_hook = rcu_dereference(br_multicast_handle_hook); ++ if (!__br_get(multicast_handle_hook, true, p, skb)) ++ goto out; ++ /* QCA qca-mcs support - End */ ++ + mdst = br_mdb_get(brmctx, skb, vid); + if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && + br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) { +@@ -190,8 +212,15 @@ int br_handle_frame_finish(struct net *n + } + break; + case BR_PKT_UNICAST: +- dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid); +- break; ++ /* QCA qca-mcs support - Start */ ++ pdst = __br_get(get_dst_hook, NULL, p, &skb); ++ if (pdst) { ++ if (!skb) ++ goto out; ++ } else { ++ /* QCA qca-mcs support - End */ ++ dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid); ++ } + default: + break; + } +@@ -206,6 +235,13 @@ int br_handle_frame_finish(struct net *n + dst->used = now; + br_forward(dst->dst, skb, local_rcv, false); + } else { ++ /* QCA qca-mcs support - Start */ ++ if (pdst) { ++ br_forward(pdst, skb, local_rcv, false); ++ goto out; ++ } ++ /* QCA qca-mcs support - End */ ++ + if (!mcast_hit) + br_flood(br, skb, pkt_type, local_rcv, false, vid); + else +--- a/include/linux/mroute.h ++++ b/include/linux/mroute.h +@@ -92,4 +92,44 @@ struct rtmsg; + int ipmr_get_route(struct net *net, struct sk_buff *skb, + __be32 saddr, __be32 daddr, + struct rtmsg *rtm, u32 portid); ++ ++/* QCA ECM qca-mcs support - Start */ ++#define IPMR_MFC_EVENT_UPDATE 1 ++#define IPMR_MFC_EVENT_DELETE 2 ++ ++/* ++ * Callback to registered modules in the event of updates to a multicast group ++ */ ++typedef void (*ipmr_mfc_event_offload_callback_t)(__be32 origin, __be32 group, ++ u32 max_dest_dev, ++ u32 dest_dev_idx[], ++ u8 op); ++ ++/* ++ * Register the callback used to inform offload modules when updates occur to ++ * MFC. The callback is registered by offload modules ++ */ ++extern bool ipmr_register_mfc_event_offload_callback( ++ ipmr_mfc_event_offload_callback_t mfc_offload_cb); ++ ++/* ++ * De-Register the callback used to inform offload modules when updates occur ++ * to MFC ++ */ ++extern void ipmr_unregister_mfc_event_offload_callback(void); ++ ++/* ++ * Find the destination interface list, given a multicast group and source ++ */ ++extern int ipmr_find_mfc_entry(struct net *net, __be32 origin, __be32 group, ++ u32 max_dst_cnt, u32 dest_dev[]); ++ ++/* ++ * Out-of-band multicast statistics update for flows that are offloaded from ++ * Linux ++ */ ++extern int ipmr_mfc_stats_update(struct net *net, __be32 origin, __be32 group, ++ u64 pkts_in, u64 bytes_in, ++ u64 pkts_out, u64 bytes_out); ++/* QCA ECM qca-mcs support - End */ + #endif +--- a/include/linux/mroute6.h ++++ b/include/linux/mroute6.h +@@ -137,4 +137,47 @@ static inline int ip6mr_sk_ioctl(struct + return 1; + } + #endif ++ ++/* QCA qca-mcs support - Start */ ++#define IP6MR_MFC_EVENT_UPDATE 1 ++#define IP6MR_MFC_EVENT_DELETE 2 ++ ++/* ++ * Callback to registered modules in the event of updates to a multicast group ++ */ ++typedef void (*ip6mr_mfc_event_offload_callback_t)(struct in6_addr *origin, ++ struct in6_addr *group, ++ u32 max_dest_dev, ++ u32 dest_dev_idx[], ++ uint8_t op); ++ ++/* ++ * Register the callback used to inform offload modules when updates occur ++ * to MFC. The callback is registered by offload modules ++ */ ++extern bool ip6mr_register_mfc_event_offload_callback( ++ ip6mr_mfc_event_offload_callback_t mfc_offload_cb); ++ ++/* ++ * De-Register the callback used to inform offload modules when updates occur ++ * to MFC ++ */ ++extern void ip6mr_unregister_mfc_event_offload_callback(void); ++ ++/* ++ * Find the destination interface list given a multicast group and source ++ */ ++extern int ip6mr_find_mfc_entry(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, u32 max_dst_cnt, ++ u32 dest_dev[]); ++ ++/* ++ * Out-of-band multicast statistics update for flows that are offloaded from ++ * Linux ++ */ ++extern int ip6mr_mfc_stats_update(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, uint64_t pkts_in, ++ uint64_t bytes_in, uint64_t pkts_out, ++ uint64_t bytes_out); ++/* QCA qca-mcs support - End */ + #endif +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -89,6 +89,9 @@ static struct net_device *vif_dev_read(c + /* Special spinlock for queue of unresolved entries */ + static DEFINE_SPINLOCK(mfc_unres_lock); + ++/* spinlock for offload */ ++static DEFINE_SPINLOCK(lock); /* QCA ECM qca-mcs support */ ++ + /* We return to original Alan's scheme. Hash table of resolved + * entries is changed only in process context and protected + * with weak lock mrt_lock. Queue of unresolved entries is protected +@@ -112,6 +115,9 @@ static void mroute_netlink_event(struct + static void igmpmsg_netlink_event(const struct mr_table *mrt, struct sk_buff *pkt); + static void mroute_clean_tables(struct mr_table *mrt, int flags); + static void ipmr_expire_process(struct timer_list *t); ++static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt, __be32 origin, ++ __be32 mcastgrp); ++static ipmr_mfc_event_offload_callback_t __rcu ipmr_mfc_event_offload_callback; /* QCA ECM qca-mcs support */ + + #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES + #define ipmr_for_each_table(mrt, net) \ +@@ -223,6 +229,80 @@ static int ipmr_rule_fill(struct fib_rul + return 0; + } + ++/* QCA ECM qca-mcs support - Start */ ++/* ipmr_sync_entry_update() ++ * Call the registered offload callback to report an update to a multicast ++ * route entry. The callback receives the list of destination interfaces and ++ * the interface count ++ */ ++static void ipmr_sync_entry_update(struct mr_table *mrt, ++ struct mfc_cache *cache) ++{ ++ int vifi, dest_if_count = 0; ++ u32 dest_dev[MAXVIFS]; ++ __be32 origin; ++ __be32 group; ++ ipmr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ memset(dest_dev, 0, sizeof(dest_dev)); ++ ++ origin = cache->mfc_origin; ++ group = cache->mfc_mcastgrp; ++ ++ spin_lock(&mrt_lock); ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ if (dest_if_count == MAXVIFS) { ++ spin_unlock(&mrt_lock); ++ return; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ return; ++ } ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ spin_unlock(&mrt_lock); ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(group, origin, dest_if_count, dest_dev, ++ IPMR_MFC_EVENT_UPDATE); ++ rcu_read_unlock(); ++} ++ ++/* ipmr_sync_entry_delete() ++ * Call the registered offload callback to inform of a multicast route entry ++ * delete event ++ */ ++static void ipmr_sync_entry_delete(u32 origin, u32 group) ++{ ++ ipmr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(group, origin, 0, NULL, IPMR_MFC_EVENT_DELETE); ++ rcu_read_unlock(); ++} ++/* QCA ECM qca-mcs support - End */ ++ + static const struct fib_rules_ops __net_initconst ipmr_rules_ops_template = { + .family = RTNL_FAMILY_IPMR, + .rule_size = sizeof(struct ipmr_rule), +@@ -236,6 +316,156 @@ static const struct fib_rules_ops __net_ + .owner = THIS_MODULE, + }; + ++/* QCA ECM qca-mcs support - Start */ ++/* ipmr_register_mfc_event_offload_callback() ++ * Register the IPv4 Multicast update offload callback with IPMR ++ */ ++bool ipmr_register_mfc_event_offload_callback( ++ ipmr_mfc_event_offload_callback_t mfc_offload_cb) ++{ ++ ipmr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ipmr_mfc_event_offload_callback); ++ ++ if (offload_update_cb_f) { ++ rcu_read_unlock(); ++ return false; ++ } ++ rcu_read_unlock(); ++ ++ spin_lock(&lock); ++ rcu_assign_pointer(ipmr_mfc_event_offload_callback, mfc_offload_cb); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++ return true; ++} ++EXPORT_SYMBOL(ipmr_register_mfc_event_offload_callback); ++ ++/* ipmr_unregister_mfc_event_offload_callback() ++ * De-register the IPv4 Multicast update offload callback with IPMR ++ */ ++void ipmr_unregister_mfc_event_offload_callback(void) ++{ ++ spin_lock(&lock); ++ rcu_assign_pointer(ipmr_mfc_event_offload_callback, NULL); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL(ipmr_unregister_mfc_event_offload_callback); ++ ++/* ipmr_find_mfc_entry() ++ * Returns destination interface list for a particular multicast flow, and ++ * the number of interfaces in the list ++ */ ++int ipmr_find_mfc_entry(struct net *net, __be32 origin, __be32 group, ++ u32 max_dest_cnt, u32 dest_dev[]) ++{ ++ int vifi, dest_if_count = 0; ++ struct mr_table *mrt; ++ struct mfc_cache *cache; ++ ++ mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); ++ if (!mrt) ++ return -ENOENT; ++ ++ rcu_read_lock(); ++ cache = ipmr_cache_find(mrt, origin, group); ++ if (!cache) { ++ rcu_read_unlock(); ++ return -ENOENT; ++ } ++ ++ spin_lock(&mrt_lock); ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ ++ /* We have another valid destination interface entry. Check if ++ * the number of the destination interfaces for the route is ++ * exceeding the size of the array given to us ++ */ ++ if (dest_if_count == max_dest_cnt) { ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ ++ return dest_if_count; ++} ++EXPORT_SYMBOL(ipmr_find_mfc_entry); ++ ++/* ipmr_mfc_stats_update() ++ * Update the MFC/VIF statistics for offloaded flows ++ */ ++int ipmr_mfc_stats_update(struct net *net, __be32 origin, __be32 group, ++ u64 pkts_in, u64 bytes_in, ++ u64 pkts_out, u64 bytes_out) ++{ ++ int vif, vifi; ++ struct mr_table *mrt; ++ struct mfc_cache *cache; ++ ++ mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); ++ if (!mrt) ++ return -ENOENT; ++ ++ rcu_read_lock(); ++ cache = ipmr_cache_find(mrt, origin, group); ++ if (!cache) { ++ rcu_read_unlock(); ++ return -ENOENT; ++ } ++ ++ vif = cache->_c.mfc_parent; ++ ++ spin_lock(&mrt_lock); ++ if (!VIF_EXISTS(mrt, vif)) { ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ ++ mrt->vif_table[vif].pkt_in += pkts_in; ++ mrt->vif_table[vif].bytes_in += bytes_in; ++ cache->_c.mfc_un.res.pkt += pkts_out; ++ cache->_c.mfc_un.res.bytes += bytes_out; ++ ++ for (vifi = cache->_c.mfc_un.res.minvif; ++ vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if ((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255)) { ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ return -EINVAL; ++ } ++ mrt->vif_table[vifi].pkt_out += pkts_out; ++ mrt->vif_table[vifi].bytes_out += bytes_out; ++ } ++ } ++ spin_unlock(&mrt_lock); ++ rcu_read_unlock(); ++ ++ return 0; ++} ++EXPORT_SYMBOL(ipmr_mfc_stats_update); ++/* QCA ECM qca-mcs support - End */ ++ + static int __net_init ipmr_rules_init(struct net *net) + { + struct fib_rules_ops *ops; +@@ -1191,6 +1421,10 @@ static int ipmr_mfc_delete(struct mr_tab + call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, c, mrt->id); + mroute_netlink_event(mrt, c, RTM_DELROUTE); + mr_cache_put(&c->_c); ++ /* QCA ECM qca-mcs support - Start */ ++ /* Inform offload modules of the delete event */ ++ ipmr_sync_entry_delete(c->mfc_origin, c->mfc_mcastgrp); ++ /* QCA ECM qca-mcs support - End */ + + return 0; + } +@@ -1221,6 +1455,10 @@ static int ipmr_mfc_add(struct net *net, + call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, c, + mrt->id); + mroute_netlink_event(mrt, c, RTM_NEWROUTE); ++ /* QCA ECM qca-mcs support - Start */ ++ /* Inform offload modules of the update event */ ++ ipmr_sync_entry_update(mrt, c); ++ /* QCA ECM qca-mcs support - End */ + return 0; + } + +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -74,6 +74,9 @@ static struct net_device *vif_dev_read(c + /* Special spinlock for queue of unresolved entries */ + static DEFINE_SPINLOCK(mfc_unres_lock); + ++/* Spinlock for offload */ ++static DEFINE_SPINLOCK(lock); /* QCA qca-mcs support */ ++ + /* We return to original Alan's scheme. Hash table of resolved + entries is changed only in process context and protected + with weak lock mrt_lock. Queue of unresolved entries is protected +@@ -101,6 +104,13 @@ static int ip6mr_rtm_dumproute(struct sk + struct netlink_callback *cb); + static void mroute_clean_tables(struct mr_table *mrt, int flags); + static void ipmr_expire_process(struct timer_list *t); ++/* QCA qca-mcs support - Start */ ++static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt, ++ const struct in6_addr *origin, ++ const struct in6_addr *mcastgrp); ++static ip6mr_mfc_event_offload_callback_t __rcu ++ ip6mr_mfc_event_offload_callback; ++/* QCA qca-mcs support - End */ + + #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES + #define ip6mr_for_each_table(mrt, net) \ +@@ -375,6 +385,84 @@ static struct mfc6_cache_cmp_arg ip6mr_m + .mf6c_mcastgrp = IN6ADDR_ANY_INIT, + }; + ++/* QCA qca-mcs support - Start */ ++/* ip6mr_sync_entry_update() ++ * Call the registered offload callback to report an update to a multicast ++ * route entry. The callback receives the list of destination interfaces and ++ * the interface count ++ */ ++static void ip6mr_sync_entry_update(struct mr_table *mrt, ++ struct mfc6_cache *cache) ++{ ++ int vifi, dest_if_count = 0; ++ u32 dest_dev[MAXMIFS]; ++ struct in6_addr mc_origin, mc_group; ++ ip6mr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ memset(dest_dev, 0, sizeof(dest_dev)); ++ ++ spin_lock(&mrt_lock); ++ ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ ++ if (dest_if_count == MAXMIFS) { ++ spin_unlock(&mrt_lock); ++ return; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ return; ++ } ++ ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ ++ memcpy(&mc_origin, &cache->mf6c_origin, sizeof(struct in6_addr)); ++ memcpy(&mc_group, &cache->mf6c_mcastgrp, sizeof(struct in6_addr)); ++ spin_unlock(&mrt_lock); ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(&mc_group, &mc_origin, dest_if_count, dest_dev, ++ IP6MR_MFC_EVENT_UPDATE); ++ rcu_read_unlock(); ++} ++ ++/* ip6mr_sync_entry_delete() ++ * Call the registered offload callback to inform of a multicast route entry ++ * delete event ++ */ ++static void ip6mr_sync_entry_delete(struct in6_addr *mc_origin, ++ struct in6_addr *mc_group) ++{ ++ ip6mr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback); ++ ++ if (!offload_update_cb_f) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ offload_update_cb_f(mc_group, mc_origin, 0, NULL, ++ IP6MR_MFC_EVENT_DELETE); ++ rcu_read_unlock(); ++} ++/* QCA qca-mcs support - End */ ++ + static struct mr_table_ops ip6mr_mr_table_ops = { + .rht_params = &ip6mr_rht_params, + .cmparg_any = &ip6mr_mr_table_ops_cmparg_any, +@@ -697,6 +785,151 @@ static int call_ip6mr_mfc_entry_notifier + &mfc->_c, tb_id, &net->ipv6.ipmr_seq); + } + ++/* QCA qca-mcs support - Start */ ++/* ip6mr_register_mfc_event_offload_callback() ++ * Register the IPv6 multicast update callback for offload modules ++ */ ++bool ip6mr_register_mfc_event_offload_callback( ++ ip6mr_mfc_event_offload_callback_t mfc_offload_cb) ++{ ++ ip6mr_mfc_event_offload_callback_t offload_update_cb_f; ++ ++ rcu_read_lock(); ++ offload_update_cb_f = rcu_dereference(ip6mr_mfc_event_offload_callback); ++ ++ if (offload_update_cb_f) { ++ rcu_read_unlock(); ++ return false; ++ } ++ rcu_read_unlock(); ++ ++ spin_lock(&lock); ++ rcu_assign_pointer(ip6mr_mfc_event_offload_callback, mfc_offload_cb); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++ return true; ++} ++EXPORT_SYMBOL(ip6mr_register_mfc_event_offload_callback); ++ ++/* ip6mr_unregister_mfc_event_offload_callback() ++ * De-register the IPv6 multicast update callback for offload modules ++ */ ++void ip6mr_unregister_mfc_event_offload_callback(void) ++{ ++ spin_lock(&lock); ++ rcu_assign_pointer(ip6mr_mfc_event_offload_callback, NULL); ++ spin_unlock(&lock); ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL(ip6mr_unregister_mfc_event_offload_callback); ++ ++/* ip6mr_find_mfc_entry() ++ * Return the destination interface list for a particular multicast flow, and ++ * the number of interfaces in the list ++ */ ++int ip6mr_find_mfc_entry(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, u32 max_dest_cnt, ++ u32 dest_dev[]) ++{ ++ int vifi, dest_if_count = 0; ++ struct mr_table *mrt; ++ struct mfc6_cache *cache; ++ ++ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); ++ if (!mrt) ++ return -ENOENT; ++ ++ spin_lock(&mrt_lock); ++ cache = ip6mr_cache_find(mrt, origin, group); ++ if (!cache) { ++ spin_unlock(&mrt_lock); ++ return -ENOENT; ++ } ++ ++ for (vifi = 0; vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if (!((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255))) { ++ continue; ++ } ++ ++ /* We have another valid destination interface entry. Check if ++ * the number of the destination interfaces for the route is ++ * exceeding the size of the array given to us ++ */ ++ if (dest_if_count == max_dest_cnt) { ++ spin_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ ++ dest_dev[dest_if_count] = mrt->vif_table[vifi].dev->ifindex; ++ dest_if_count++; ++ } ++ spin_unlock(&mrt_lock); ++ ++ return dest_if_count; ++} ++EXPORT_SYMBOL(ip6mr_find_mfc_entry); ++ ++/* ip6mr_mfc_stats_update() ++ * Update the MFC/VIF statistics for offloaded flows ++ */ ++int ip6mr_mfc_stats_update(struct net *net, struct in6_addr *origin, ++ struct in6_addr *group, u64 pkts_in, ++ u64 bytes_in, uint64_t pkts_out, ++ u64 bytes_out) ++{ ++ int vif, vifi; ++ struct mr_table *mrt; ++ struct mfc6_cache *cache; ++ ++ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); ++ ++ if (!mrt) ++ return -ENOENT; ++ ++ spin_lock(&mrt_lock); ++ cache = ip6mr_cache_find(mrt, origin, group); ++ if (!cache) { ++ spin_unlock(&mrt_lock); ++ return -ENOENT; ++ } ++ ++ vif = cache->_c.mfc_parent; ++ ++ if (!VIF_EXISTS(mrt, vif)) { ++ spin_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ ++ mrt->vif_table[vif].pkt_in += pkts_in; ++ mrt->vif_table[vif].bytes_in += bytes_in; ++ cache->_c.mfc_un.res.pkt += pkts_out; ++ cache->_c.mfc_un.res.bytes += bytes_out; ++ ++ for (vifi = cache->_c.mfc_un.res.minvif; ++ vifi < cache->_c.mfc_un.res.maxvif; vifi++) { ++ if ((cache->_c.mfc_un.res.ttls[vifi] > 0) && ++ (cache->_c.mfc_un.res.ttls[vifi] < 255)) { ++ if (!VIF_EXISTS(mrt, vifi)) { ++ spin_unlock(&mrt_lock); ++ return -EINVAL; ++ } ++ mrt->vif_table[vifi].pkt_out += pkts_out; ++ mrt->vif_table[vifi].bytes_out += bytes_out; ++ } ++ } ++ ++ spin_unlock(&mrt_lock); ++ return 0; ++} ++EXPORT_SYMBOL(ip6mr_mfc_stats_update); ++/* QCA qca-mcs support - End */ ++ + /* Delete a VIF entry */ + static int mif6_delete(struct mr_table *mrt, int vifi, int notify, + struct list_head *head) +@@ -1221,6 +1454,7 @@ static int ip6mr_mfc_delete(struct mr_ta + int parent) + { + struct mfc6_cache *c; ++ struct in6_addr mc_origin, mc_group; /* QCA qca-mcs support */ + + /* The entries are added/deleted only under RTNL */ + rcu_read_lock(); +@@ -1229,6 +1463,11 @@ static int ip6mr_mfc_delete(struct mr_ta + rcu_read_unlock(); + if (!c) + return -ENOENT; ++ ++ /* QCA qca-mcs support - Start */ ++ memcpy(&mc_origin, &c->mf6c_origin, sizeof(struct in6_addr)); ++ memcpy(&mc_group, &c->mf6c_mcastgrp, sizeof(struct in6_addr)); ++ /* QCA qca-mcs support - End */ + rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params); + list_del_rcu(&c->_c.list); + +@@ -1236,6 +1475,11 @@ static int ip6mr_mfc_delete(struct mr_ta + FIB_EVENT_ENTRY_DEL, c, mrt->id); + mr6_netlink_event(mrt, c, RTM_DELROUTE); + mr_cache_put(&c->_c); ++ /* QCA qca-mcs support - Start */ ++ /* Inform offload modules of the delete event */ ++ ip6mr_sync_entry_delete(&mc_origin, &mc_group); ++ /* QCA qca-mcs support - End */ ++ + return 0; + } + +@@ -1457,6 +1701,10 @@ static int ip6mr_mfc_add(struct net *net + call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, + c, mrt->id); + mr6_netlink_event(mrt, c, RTM_NEWROUTE); ++ /* QCA qca-mcs support - Start */ ++ /* Inform offload modules of the update event */ ++ ip6mr_sync_entry_update(mrt, c); ++ /* QCA qca-mcs support - End */ + return 0; + } + diff --git a/6.6/target/linux/qualcommax/patches-6.6/0605-1-qca-nss-cfi-support.patch b/6.6/target/linux/qualcommax/patches-6.6/0605-1-qca-nss-cfi-support.patch new file mode 100644 index 000000000..a0ed16e38 --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0605-1-qca-nss-cfi-support.patch @@ -0,0 +1,127 @@ +--- a/crypto/authenc.c ++++ b/crypto/authenc.c +@@ -417,6 +417,8 @@ static int crypto_authenc_create(struct + enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + ++ inst->alg.base.cra_flags |= (auth_base->cra_flags | ++ enc->base.cra_flags) & CRYPTO_ALG_NOSUPP_SG; + inst->alg.base.cra_priority = enc->base.cra_priority * 10 + + auth_base->cra_priority; + inst->alg.base.cra_blocksize = enc->base.cra_blocksize; +--- a/include/linux/crypto.h ++++ b/include/linux/crypto.h +@@ -101,6 +101,11 @@ + #define CRYPTO_NOLOAD 0x00008000 + + /* ++ * Set this flag if algorithm does not support SG list transforms ++ */ ++#define CRYPTO_ALG_NOSUPP_SG 0x0000c000 ++ ++/* + * The algorithm may allocate memory during request processing, i.e. during + * encryption, decryption, or hashing. Users can request an algorithm with this + * flag unset if they can't handle memory allocation failures. +--- a/net/ipv4/esp4.c ++++ b/net/ipv4/esp4.c +@@ -3,6 +3,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -658,6 +658,7 @@ static int esp_output(struct xfrm_state + struct ip_esp_hdr *esph; + struct crypto_aead *aead; + struct esp_info esp; ++ bool nosupp_sg; + + esp.inplace = true; + +@@ -669,6 +670,11 @@ static int esp_output(struct xfrm_state + aead = x->data; + alen = crypto_aead_authsize(aead); + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ return -ENOMEM; ++ } ++ + esp.tfclen = 0; + if (x->tfcpad) { + struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); +@@ -890,6 +896,7 @@ static int esp_input(struct xfrm_state * + u8 *iv; + struct scatterlist *sg; + int err = -EINVAL; ++ bool nosupp_sg; + + if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) + goto out; +@@ -897,6 +904,12 @@ static int esp_input(struct xfrm_state * + if (elen <= 0) + goto out; + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ + assoclen = sizeof(struct ip_esp_hdr); + seqhilen = 0; + +--- a/net/ipv6/esp6.c ++++ b/net/ipv6/esp6.c +@@ -15,6 +15,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -696,6 +696,7 @@ static int esp6_output(struct xfrm_state + struct ip_esp_hdr *esph; + struct crypto_aead *aead; + struct esp_info esp; ++ bool nosupp_sg; + + esp.inplace = true; + +@@ -707,6 +708,11 @@ static int esp6_output(struct xfrm_state + aead = x->data; + alen = crypto_aead_authsize(aead); + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ return -ENOMEM; ++ } ++ + esp.tfclen = 0; + if (x->tfcpad) { + struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); +@@ -934,6 +940,7 @@ static int esp6_input(struct xfrm_state + __be32 *seqhi; + u8 *iv; + struct scatterlist *sg; ++ bool nosupp_sg; + + if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) { + ret = -EINVAL; +@@ -945,6 +952,12 @@ static int esp6_input(struct xfrm_state + goto out; + } + ++ nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; ++ if (nosupp_sg && skb_linearize(skb)) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ + assoclen = sizeof(struct ip_esp_hdr); + seqhilen = 0; + diff --git a/6.6/target/linux/qualcommax/patches-6.6/0611-ipv6-Fix-null-pointer-dereference-in-ipv6-output.patch b/6.6/target/linux/qualcommax/patches-6.6/0611-ipv6-Fix-null-pointer-dereference-in-ipv6-output.patch new file mode 100644 index 000000000..25f99fc4a --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/0611-ipv6-Fix-null-pointer-dereference-in-ipv6-output.patch @@ -0,0 +1,80 @@ +From eee3a7956b943dd3e23a74fbb5bfe89405eb0782 Mon Sep 17 00:00:00 2001 +From: Andrea Righi +Date: Mon, 6 Dec 2021 17:34:47 +0100 +Subject: UBUNTU: SAUCE: ipv6: fix NULL pointer dereference in ip6_output() + +It is possible to trigger a NULL pointer dereference by running the srv6 +net kselftest (tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh): + +[ 249.051216] BUG: kernel NULL pointer dereference, address: 0000000000000378 +[ 249.052331] #PF: supervisor read access in kernel mode +[ 249.053137] #PF: error_code(0x0000) - not-present page +[ 249.053960] PGD 0 P4D 0 +[ 249.054376] Oops: 0000 [#1] PREEMPT SMP NOPTI +[ 249.055083] CPU: 1 PID: 21 Comm: ksoftirqd/1 Tainted: G E 5.16.0-rc4 #2 +[ 249.056328] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014 +[ 249.057632] RIP: 0010:ip6_forward+0x53c/0xab0 +[ 249.058354] Code: 49 c7 44 24 20 00 00 00 00 48 83 e0 fe 48 8b 40 30 48 3d 70 b2 b5 81 0f 85 b5 04 00 00 e8 7c f2 ff ff 41 89 c5 e9 17 01 00 00 <44> 8b 93 78 03 00 00 45 85 d2 0f 85 92 fb ff ff 49 8b 54 24 10 48 +[ 249.061274] RSP: 0018:ffffc900000cbb30 EFLAGS: 00010246 +[ 249.062042] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff8881051d3400 +[ 249.063141] RDX: ffff888104bda000 RSI: 00000000000002c0 RDI: 0000000000000000 +[ 249.064264] RBP: ffffc900000cbbc8 R08: 0000000000000000 R09: 0000000000000000 +[ 249.065376] R10: 0000000000000040 R11: 0000000000000000 R12: ffff888103409800 +[ 249.066498] R13: ffff8881051d3410 R14: ffff888102725280 R15: ffff888103525000 +[ 249.067619] FS: 0000000000000000(0000) GS:ffff88813bc80000(0000) knlGS:0000000000000000 +[ 249.068881] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 249.069777] CR2: 0000000000000378 CR3: 0000000104980000 CR4: 0000000000750ee0 +[ 249.070907] PKRU: 55555554 +[ 249.071337] Call Trace: +[ 249.071730] +[ 249.072070] ? debug_smp_processor_id+0x17/0x20 +[ 249.072807] seg6_input_core+0x2bb/0x2d0 +[ 249.073436] ? _raw_spin_unlock_irqrestore+0x29/0x40 +[ 249.074225] seg6_input+0x3b/0x130 +[ 249.074768] lwtunnel_input+0x5e/0xa0 +[ 249.075357] ip_rcv+0x17b/0x190 +[ 249.075867] ? update_load_avg+0x82/0x600 +[ 249.076514] __netif_receive_skb_one_core+0x86/0xa0 +[ 249.077231] __netif_receive_skb+0x15/0x60 +[ 249.077843] process_backlog+0x97/0x160 +[ 249.078389] __napi_poll+0x31/0x170 +[ 249.078912] net_rx_action+0x229/0x270 +[ 249.079506] __do_softirq+0xef/0x2ed +[ 249.080085] run_ksoftirqd+0x37/0x50 +[ 249.080663] smpboot_thread_fn+0x193/0x230 +[ 249.081312] kthread+0x17a/0x1a0 +[ 249.081847] ? smpboot_register_percpu_thread+0xe0/0xe0 +[ 249.082677] ? set_kthread_struct+0x50/0x50 +[ 249.083340] ret_from_fork+0x22/0x30 +[ 249.083926] +[ 249.090295] ---[ end trace 1998d7ba5965a365 ]--- + +It looks like commit 0857d6f8c759 ("ipv6: When forwarding count rx stats +on the orig netdev") tries to determine the right netdev to account the +rx stats, but in this particular case it's failing and the netdev is +NULL. + +Fallback to the previous method of determining the netdev interface (via +skb->dev) to account the rx stats when the orig netdev can't be +determined. + +Fixes: 0857d6f8c759 ("ipv6: When forwarding count rx stats on the orig netdev") +Signed-off-by: Andrea Righi +(cherry picked from https://lore.kernel.org/lkml/20211206163447.991402-1-andrea.righi@canonical.com/T/#u) +Signed-off-by: Andrea Righi +--- + net/ipv6/ip6_output.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -498,6 +498,9 @@ int ip6_forward(struct sk_buff *skb) + u32 mtu; + + idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif)); ++ if (unlikely(!idev)) ++ idev = __in6_dev_get_safely(skb->dev); ++ + if (net->ipv6.devconf_all->forwarding == 0) + goto error; + diff --git a/6.6/target/linux/qualcommax/patches-6.6/9990-1-qca-skb_recycler-support.patch b/6.6/target/linux/qualcommax/patches-6.6/9990-1-qca-skb_recycler-support.patch new file mode 100644 index 000000000..e59b5e539 --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/9990-1-qca-skb_recycler-support.patch @@ -0,0 +1,384 @@ +--- a/include/linux/cpuhotplug.h ++++ b/include/linux/cpuhotplug.h +@@ -94,6 +94,7 @@ enum cpuhp_state { + CPUHP_RADIX_DEAD, + CPUHP_PAGE_ALLOC, + CPUHP_NET_DEV_DEAD, ++ CPUHP_SKB_RECYCLER_DEAD, + CPUHP_PCI_XGENE_DEAD, + CPUHP_IOMMU_IOVA_DEAD, + CPUHP_LUSTRE_CFS_DEAD, +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -1065,6 +1065,10 @@ struct sk_buff { + /* only useable after checking ->active_extensions != 0 */ + struct skb_ext *extensions; + #endif ++ ++#ifdef CONFIG_DEBUG_OBJECTS_SKBUFF ++ void *free_addr; ++#endif + }; + + /* if you move pkt_type around you also must adapt those constants */ +@@ -1250,7 +1254,7 @@ static inline void kfree_skb_list(struct sk_buff *segs) + kfree_skb_list_reason(segs, SKB_DROP_REASON_NOT_SPECIFIED); + } + +-#ifdef CONFIG_TRACEPOINTS ++#ifdef CONFIG_SKB_RECYCLER + void consume_skb(struct sk_buff *skb); + #else + static inline void consume_skb(struct sk_buff *skb) +@@ -1262,6 +1266,9 @@ static inline void consume_skb(struct sk_buff *skb) + void __consume_stateless_skb(struct sk_buff *skb); + void __kfree_skb(struct sk_buff *skb); + extern struct kmem_cache *skbuff_cache; ++extern void kfree_skbmem(struct sk_buff *skb); ++extern void skb_release_data(struct sk_buff *skb, enum skb_drop_reason reason, ++ bool napi_safe); + + void kfree_skb_partial(struct sk_buff *skb, bool head_stolen); + bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from, +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -369,6 +369,27 @@ config NET_FLOW_LIMIT + with many clients some protection against DoS by a single (spoofed) + flow that greatly exceeds average workload. + ++config SKB_RECYCLER ++ bool "Generic skb recycling" ++ default y ++ help ++ SKB_RECYCLER is used to implement RX-to-RX skb recycling. ++ This config enables the recycling scheme for bridging and ++ routing workloads. It can reduce skbuff freeing or ++ reallocation overhead. ++ ++config SKB_RECYCLER_MULTI_CPU ++ bool "Cross-CPU recycling for CPU-locked workloads" ++ depends on SMP && SKB_RECYCLER ++ default n ++ ++config ALLOC_SKB_PAGE_FRAG_DISABLE ++ bool "Disable page fragment based skbuff payload allocations" ++ depends on !SKB_RECYCLER ++ default n ++ help ++ Disable page fragment based allocations for skbuff payloads. ++ + menu "Network testing" + + config NET_PKTGEN +--- a/net/core/Makefile ++++ b/net/core/Makefile +@@ -41,3 +41,4 @@ obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o + obj-$(CONFIG_BPF_SYSCALL) += sock_map.o + obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o + obj-$(CONFIG_OF) += of_net.o ++obj-$(CONFIG_SKB_RECYCLER) += skbuff_recycle.o +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -6016,10 +6016,16 @@ static int process_backlog(struct napi_struct *napi, int quota) + + napi->weight = READ_ONCE(dev_rx_weight); + while (again) { +- struct sk_buff *skb; ++ struct sk_buff *skb, *next_skb; + + while ((skb = __skb_dequeue(&sd->process_queue))) { + rcu_read_lock(); ++ ++ next_skb = skb_peek(&sd->process_queue); ++ if (likely(next_skb)) { ++ prefetch(next_skb->data); ++ } ++ + __netif_receive_skb(skb); + rcu_read_unlock(); + input_queue_head_incr(sd); +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -87,6 +87,31 @@ + + #include "dev.h" + #include "sock_destructor.h" ++#include "skbuff_recycle.h" ++ ++struct kmem_cache *skb_data_cache; ++/* ++ * For low memory profile, NSS_SKB_FIXED_SIZE_2K is enabled and ++ * CONFIG_SKB_RECYCLER is disabled. For premium and enterprise profile ++ * CONFIG_SKB_RECYCLER is enabled and NSS_SKB_FIXED_SIZE_2K is disabled. ++ * Irrespective of NSS_SKB_FIXED_SIZE_2K enabled/disabled, the ++ * CONFIG_SKB_RECYCLER and __LP64__ determines the value of SKB_DATA_CACHE_SIZE ++ */ ++#if defined(CONFIG_SKB_RECYCLER) ++/* ++ * 2688 for 64bit arch, 2624 for 32bit arch ++ */ ++#define SKB_DATA_CACHE_SIZE (SKB_DATA_ALIGN(SKB_RECYCLE_SIZE + NET_SKB_PAD) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) ++#else ++/* ++ * 2368 for 64bit arch, 2176 for 32bit arch ++ */ ++#if defined(__LP64__) ++#define SKB_DATA_CACHE_SIZE ((SKB_DATA_ALIGN(1984 + NET_SKB_PAD)) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) ++#else ++#define SKB_DATA_CACHE_SIZE ((SKB_DATA_ALIGN(1856 + NET_SKB_PAD)) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) ++#endif ++#endif + + struct kmem_cache *skbuff_cache __ro_after_init; + static struct kmem_cache *skbuff_fclone_cache __ro_after_init; +@@ -551,21 +576,20 @@ static void *kmalloc_reserve(unsigned int *size, gfp_t flags, int node, + bool *pfmemalloc) + { + bool ret_pfmemalloc = false; +- size_t obj_size; ++ unsigned int obj_size = *size; + void *obj; + + obj_size = SKB_HEAD_ALIGN(*size); +- if (obj_size <= SKB_SMALL_HEAD_CACHE_SIZE && +- !(flags & KMALLOC_NOT_NORMAL_BITS)) { +- obj = kmem_cache_alloc_node(skb_small_head_cache, +- flags | __GFP_NOMEMALLOC | __GFP_NOWARN, +- node); +- *size = SKB_SMALL_HEAD_CACHE_SIZE; ++ if (obj_size > SZ_2K && obj_size <= SKB_DATA_CACHE_SIZE) { ++ obj = kmem_cache_alloc_node(skb_data_cache, ++ flags | __GFP_NOMEMALLOC | __GFP_NOWARN, ++ node); ++ *size = SKB_DATA_CACHE_SIZE; + if (obj || !(gfp_pfmemalloc_allowed(flags))) + goto out; + /* Try again but now we are using pfmemalloc reserves */ + ret_pfmemalloc = true; +- obj = kmem_cache_alloc_node(skb_small_head_cache, flags, node); ++ obj = kmem_cache_alloc_node(skb_data_cache, flags, node); + goto out; + } + +@@ -648,10 +671,12 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, + * aligned memory blocks, unless SLUB/SLAB debug is enabled. + * Both skb->head and skb_shared_info are cache line aligned. + */ ++ size = SKB_DATA_ALIGN(size); ++ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + data = kmalloc_reserve(&size, gfp_mask, node, &pfmemalloc); + if (unlikely(!data)) + goto nodata; +- /* kmalloc_size_roundup() might give us more room than requested. ++ /* kmalloc_reserve(size) might give us more room than requested. + * Put skb_shared_info exactly at the end of allocated zone, + * to allow max possible filling before reallocation. + */ +@@ -686,7 +711,7 @@ EXPORT_SYMBOL(__alloc_skb); + /** + * __netdev_alloc_skb - allocate an skbuff for rx on a specific device + * @dev: network device to receive on +- * @len: length to allocate ++ * @length: length to allocate + * @gfp_mask: get_free_pages mask, passed to alloc_skb + * + * Allocate a new &sk_buff and assign it a usage count of one. The +@@ -696,29 +721,53 @@ EXPORT_SYMBOL(__alloc_skb); + * + * %NULL is returned if there is no free memory. + */ +-struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len, +- gfp_t gfp_mask) ++struct sk_buff *__netdev_alloc_skb(struct net_device *dev, ++ unsigned int length, gfp_t gfp_mask) + { +- struct page_frag_cache *nc; + struct sk_buff *skb; ++ unsigned int len = length; ++ ++#ifdef CONFIG_SKB_RECYCLER ++ skb = skb_recycler_alloc(dev, length); ++ if (likely(skb)) ++ return skb; ++ ++ len = SKB_RECYCLE_SIZE; ++ if (unlikely(length > SKB_RECYCLE_SIZE)) ++ len = length; ++ ++ skb = __alloc_skb(len + NET_SKB_PAD, gfp_mask, ++ SKB_ALLOC_RX, NUMA_NO_NODE); ++ if (!skb) ++ goto skb_fail; ++ goto skb_success; ++#else ++ struct page_frag_cache *nc; + bool pfmemalloc; ++ bool page_frag_alloc_enable = true; + void *data; + + len += NET_SKB_PAD; + ++ ++#ifdef CONFIG_ALLOC_SKB_PAGE_FRAG_DISABLE ++ page_frag_alloc_enable = false; ++#endif + /* If requested length is either too small or too big, + * we use kmalloc() for skb->head allocation. + */ + if (len <= SKB_WITH_OVERHEAD(1024) || + len > SKB_WITH_OVERHEAD(PAGE_SIZE) || +- (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) { ++ (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA)) || ++ !page_frag_alloc_enable) { + skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE); + if (!skb) + goto skb_fail; + goto skb_success; + } + +- len = SKB_HEAD_ALIGN(len); ++ len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); ++ len = SKB_DATA_ALIGN(len); + + if (sk_memalloc_socks()) + gfp_mask |= __GFP_MEMALLOC; +@@ -747,6 +796,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len, + if (pfmemalloc) + skb->pfmemalloc = 1; + skb->head_frag = 1; ++#endif + + skb_success: + skb_reserve(skb, NET_SKB_PAD); +@@ -817,7 +867,8 @@ struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len, + data = page_frag_alloc_1k(&nc->page_small, gfp_mask); + pfmemalloc = NAPI_SMALL_PAGE_PFMEMALLOC(nc->page_small); + } else { +- len = SKB_HEAD_ALIGN(len); ++ len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); ++ len = SKB_DATA_ALIGN(len); + + data = page_frag_alloc(&nc->page, len, gfp_mask); + pfmemalloc = nc->page.pfmemalloc; +@@ -975,7 +1026,7 @@ static void skb_free_head(struct sk_buff *skb, bool napi_safe) + } + } + +-static void skb_release_data(struct sk_buff *skb, enum skb_drop_reason reason, ++void skb_release_data(struct sk_buff *skb, enum skb_drop_reason reason, + bool napi_safe) + { + struct skb_shared_info *shinfo = skb_shinfo(skb); +@@ -1018,7 +1069,7 @@ static void skb_release_data(struct sk_buff *skb, enum skb_drop_reason reason, + /* + * Free an skbuff by memory without cleaning the state. + */ +-static void kfree_skbmem(struct sk_buff *skb) ++void kfree_skbmem(struct sk_buff *skb) + { + struct sk_buff_fclones *fclones; + +@@ -1282,7 +1333,6 @@ void skb_tx_error(struct sk_buff *skb) + } + EXPORT_SYMBOL(skb_tx_error); + +-#ifdef CONFIG_TRACEPOINTS + /** + * consume_skb - free an skbuff + * @skb: buffer to free +@@ -1291,13 +1341,48 @@ EXPORT_SYMBOL(skb_tx_error); + * Functions identically to kfree_skb, but kfree_skb assumes that the frame + * is being dropped after a failure and notes that + */ ++#ifdef CONFIG_SKB_RECYCLER + void consume_skb(struct sk_buff *skb) + { + if (!skb_unref(skb)) + return; ++ prefetch(&skb->destructor); ++ ++ /*Tian: Not sure if we need to continue using this since ++ * since unref does the work in 5.4 ++ */ ++ ++ /* ++ if (likely(atomic_read(&skb->users) == 1)) ++ smp_rmb(); ++ else if (likely(!atomic_dec_and_test(&skb->users))) ++ return; ++ */ + ++ /* If possible we'd like to recycle any skb rather than just free it, ++ * but in order to do that we need to release any head state too. ++ * We don't want to do this later because we'll be in a pre-emption ++ * disabled state. ++ */ ++ skb_release_head_state(skb); ++ ++ /* Can we recycle this skb? If we can then it will be much faster ++ * for us to recycle this one later than to allocate a new one ++ * from scratch. ++ */ ++ if (likely(skb->head) && likely(skb_recycler_consume(skb))) ++ return; ++ ++#ifdef CONFIG_TRACEPOINTS + trace_consume_skb(skb, __builtin_return_address(0)); +- __kfree_skb(skb); ++#endif ++ /* We're not recycling so now we need to do the rest of what we would ++ * have done in __kfree_skb (above and beyond the skb_release_head_state ++ * that we already did). ++ */ ++ if (likely(skb->head)) ++ skb_release_data(skb, SKB_CONSUMED, false); ++ kfree_skbmem(skb); + } + EXPORT_SYMBOL(consume_skb); + #endif +@@ -2107,6 +2192,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, + if (skb_pfmemalloc(skb)) + gfp_mask |= __GFP_MEMALLOC; + ++ size = SKB_DATA_ALIGN(size); ++ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL); + if (!data) + goto nodata; +@@ -4854,6 +4941,10 @@ static void skb_extensions_init(void) {} + + void __init skb_init(void) + { ++ skb_data_cache = kmem_cache_create_usercopy("skb_data_cache", ++ SKB_DATA_CACHE_SIZE, ++ 0, SLAB_PANIC, 0, SKB_DATA_CACHE_SIZE, ++ NULL); + skbuff_cache = kmem_cache_create_usercopy("skbuff_head_cache", + sizeof(struct sk_buff), + 0, +@@ -4879,6 +4970,7 @@ void __init skb_init(void) + SKB_SMALL_HEAD_HEADROOM, + NULL); + skb_extensions_init(); ++ skb_recycler_init(); + } + + static int +@@ -6382,6 +6474,8 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, + if (skb_pfmemalloc(skb)) + gfp_mask |= __GFP_MEMALLOC; + ++ size = SKB_DATA_ALIGN(size); ++ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL); + if (!data) + return -ENOMEM; +@@ -6498,6 +6592,8 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, + if (skb_pfmemalloc(skb)) + gfp_mask |= __GFP_MEMALLOC; + ++ size = SKB_DATA_ALIGN(size); ++ size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + data = kmalloc_reserve(&size, gfp_mask, NUMA_NO_NODE, NULL); + if (!data) + return -ENOMEM; diff --git a/6.6/target/linux/qualcommax/patches-6.6/9991-arm64-dts-qcom-disable-swiotlb-for-64mb-savings.patch b/6.6/target/linux/qualcommax/patches-6.6/9991-arm64-dts-qcom-disable-swiotlb-for-64mb-savings.patch new file mode 100644 index 000000000..bb610079a --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/9991-arm64-dts-qcom-disable-swiotlb-for-64mb-savings.patch @@ -0,0 +1,99 @@ +--- a/arch/arm64/boot/dts/qcom/ipq6010-wax214.dts ++++ b/arch/arm64/boot/dts/qcom/ipq6010-wax214.dts +@@ -25,7 +25,7 @@ + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs-append = " root=/dev/ubiblock0_1"; ++ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_1"; + }; + + keys { +--- a/arch/arm64/boot/dts/qcom/ipq8070-cax1800.dts ++++ b/arch/arm64/boot/dts/qcom/ipq8070-cax1800.dts +@@ -27,7 +27,7 @@ + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs-append = " root=/dev/ubiblock0_1"; ++ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_1"; + }; + + keys { +--- a/arch/arm64/boot/dts/qcom/ipq8070-rm2-6.dts ++++ b/arch/arm64/boot/dts/qcom/ipq8070-rm2-6.dts +@@ -32,7 +32,7 @@ + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs-append = " root=/dev/ubiblock0_1"; ++ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_1"; + }; + + keys { +--- a/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq8071-ax3600.dtsi +@@ -20,7 +20,7 @@ + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs-append = " root=/dev/ubiblock0_0"; ++ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_0"; + }; + + keys { +--- a/arch/arm64/boot/dts/qcom/ipq8071-mf269.dts ++++ b/arch/arm64/boot/dts/qcom/ipq8071-mf269.dts +@@ -24,7 +24,7 @@ + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs-append = " root=/dev/ubiblock0_0"; ++ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_0"; + }; + + keys { +--- a/arch/arm64/boot/dts/qcom/ipq8072-ax880.dts ++++ b/arch/arm64/boot/dts/qcom/ipq8072-ax880.dts +@@ -29,7 +29,7 @@ + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs-append = " root=/dev/ubiblock0_1"; ++ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_1"; + }; + + keys { +--- a/arch/arm64/boot/dts/qcom/ipq8072-wax218.dts ++++ b/arch/arm64/boot/dts/qcom/ipq8072-wax218.dts +@@ -27,7 +27,7 @@ + * Netgear's U-Boot adds "ubi.mtd=rootfs root=mtd:ubi_rootfs" + * That fails to create a UBI block device, so add it here. + */ +- bootargs-append = " ubi.block=0,rootfs root=/dev/ubiblock0_1"; ++ bootargs-append = " coherent_pool=2M swiotlb=noforce ubi.block=0,rootfs root=/dev/ubiblock0_1"; + }; + + keys { +--- a/arch/arm64/boot/dts/qcom/ipq8072-wpq873.dts ++++ b/arch/arm64/boot/dts/qcom/ipq8072-wpq873.dts +@@ -31,7 +31,7 @@ + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs-append = " root=/dev/ubiblock0_1"; ++ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_1"; + }; + + keys { +--- a/arch/arm64/boot/dts/qcom/ipq8174-mx4200.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq8174-mx4200.dtsi +@@ -29,7 +29,7 @@ + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs-append = " root=/dev/ubiblock0_0"; ++ bootargs-append = " coherent_pool=2M swiotlb=noforce root=/dev/ubiblock0_0"; + }; + + keys { diff --git a/6.6/target/linux/qualcommax/patches-6.6/9999-revert-crypto-api-disallow-identical-driver-names.patch b/6.6/target/linux/qualcommax/patches-6.6/9999-revert-crypto-api-disallow-identical-driver-names.patch new file mode 100644 index 000000000..3f7f58dfe --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/9999-revert-crypto-api-disallow-identical-driver-names.patch @@ -0,0 +1,10 @@ +--- a/crypto/algapi.c ++++ b/crypto/algapi.c +@@ -341,7 +341,6 @@ __crypto_register_alg(struct crypto_alg + } + + if (!strcmp(q->cra_driver_name, alg->cra_name) || +- !strcmp(q->cra_driver_name, alg->cra_driver_name) || + !strcmp(q->cra_name, alg->cra_driver_name)) + goto err; + } diff --git a/6.6/target/linux/qualcommax/patches-6.6/9999-silence-UBI-NAND-warnings.patch b/6.6/target/linux/qualcommax/patches-6.6/9999-silence-UBI-NAND-warnings.patch new file mode 100644 index 000000000..646e683dc --- /dev/null +++ b/6.6/target/linux/qualcommax/patches-6.6/9999-silence-UBI-NAND-warnings.patch @@ -0,0 +1,13 @@ +--- a/drivers/mtd/mtdblock.c ++++ b/drivers/mtd/mtdblock.c +@@ -261,10 +261,6 @@ static int mtdblock_open(struct mtd_blkt + return 0; + } + +- if (mtd_type_is_nand(mbd->mtd)) +- pr_warn_ratelimited("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n", +- mbd->tr->name, mbd->mtd->name); +- + /* OK, it's not open. Create cache info for it */ + mtdblk->count = 1; + mutex_init(&mtdblk->cache_mutex);