[][Add macsec HW offload backport from kernel 5.18]

[Description]
Add macsec HW offload backport from kernel 5.18.

[Release-log]
N/A

Change-Id: I5b143fe620ec4bcae4075d1d85db5e41c8d48717
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5981730
diff --git a/target/linux/mediatek/patches-5.4/999-1756-06-v5.18-net-macsec-add-nla-support-for-changing-the-offloading-selection.patch b/target/linux/mediatek/patches-5.4/999-1756-06-v5.18-net-macsec-add-nla-support-for-changing-the-offloading-selection.patch
new file mode 100644
index 0000000..849d2cd
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/999-1756-06-v5.18-net-macsec-add-nla-support-for-changing-the-offloading-selection.patch
@@ -0,0 +1,253 @@
+From dcb780fb279514f268826f2e9f4df3bc75610703 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:44 +0100
+Subject: net: macsec: add nla support for changing the offloading selection
+
+MACsec offloading to underlying hardware devices is disabled by default
+(the software implementation is used). This patch adds support for
+changing this setting through the MACsec netlink interface. Many checks
+are done when enabling offloading on a given MACsec interface as there
+are limitations (it must be supported by the hardware, only a single
+interface can be offloaded on a given physical device at a time, rules
+can't be moved for now).
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/macsec.c           | 145 ++++++++++++++++++++++++++++++++++++++++-
+ include/uapi/linux/if_macsec.h |  11 ++++
+ 2 files changed, 153 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 36b0416381bf1..e515919e8687f 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -1484,6 +1484,7 @@ static const struct nla_policy macsec_genl_policy[NUM_MACSEC_ATTR] = {
+ 	[MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 },
+ 	[MACSEC_ATTR_RXSC_CONFIG] = { .type = NLA_NESTED },
+ 	[MACSEC_ATTR_SA_CONFIG] = { .type = NLA_NESTED },
++	[MACSEC_ATTR_OFFLOAD] = { .type = NLA_NESTED },
+ };
+ 
+ static const struct nla_policy macsec_genl_rxsc_policy[NUM_MACSEC_RXSC_ATTR] = {
+@@ -1501,6 +1502,10 @@ static const struct nla_policy macsec_genl_sa_policy[NUM_MACSEC_SA_ATTR] = {
+ 				 .len = MACSEC_MAX_KEY_LEN, },
+ };
+ 
++static const struct nla_policy macsec_genl_offload_policy[NUM_MACSEC_OFFLOAD_ATTR] = {
++	[MACSEC_OFFLOAD_ATTR_TYPE] = { .type = NLA_U8 },
++};
++
+ /* Offloads an operation to a device driver */
+ static int macsec_offload(int (* const func)(struct macsec_context *),
+ 			  struct macsec_context *ctx)
+@@ -2329,6 +2334,126 @@ cleanup:
+ 	return ret;
+ }
+ 
++static bool macsec_is_configured(struct macsec_dev *macsec)
++{
++	struct macsec_secy *secy = &macsec->secy;
++	struct macsec_tx_sc *tx_sc = &secy->tx_sc;
++	int i;
++
++	if (secy->n_rx_sc > 0)
++		return true;
++
++	for (i = 0; i < MACSEC_NUM_AN; i++)
++		if (tx_sc->sa[i])
++			return true;
++
++	return false;
++}
++
++static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info)
++{
++	struct nlattr *tb_offload[MACSEC_OFFLOAD_ATTR_MAX + 1];
++	enum macsec_offload offload, prev_offload;
++	int (*func)(struct macsec_context *ctx);
++	struct nlattr **attrs = info->attrs;
++	struct net_device *dev, *loop_dev;
++	const struct macsec_ops *ops;
++	struct macsec_context ctx;
++	struct macsec_dev *macsec;
++	struct net *loop_net;
++	int ret;
++
++	if (!attrs[MACSEC_ATTR_IFINDEX])
++		return -EINVAL;
++
++	if (!attrs[MACSEC_ATTR_OFFLOAD])
++		return -EINVAL;
++
++	if (nla_parse_nested_deprecated(tb_offload, MACSEC_OFFLOAD_ATTR_MAX,
++					attrs[MACSEC_ATTR_OFFLOAD],
++					macsec_genl_offload_policy, NULL))
++		return -EINVAL;
++
++	dev = get_dev_from_nl(genl_info_net(info), attrs);
++	if (IS_ERR(dev))
++		return PTR_ERR(dev);
++	macsec = macsec_priv(dev);
++
++	offload = nla_get_u8(tb_offload[MACSEC_OFFLOAD_ATTR_TYPE]);
++	if (macsec->offload == offload)
++		return 0;
++
++	/* Check if the offloading mode is supported by the underlying layers */
++	if (offload != MACSEC_OFFLOAD_OFF &&
++	    !macsec_check_offload(offload, macsec))
++		return -EOPNOTSUPP;
++
++	if (offload == MACSEC_OFFLOAD_OFF)
++		goto skip_limitation;
++
++	/* Check the physical interface isn't offloading another interface
++	 * first.
++	 */
++	for_each_net(loop_net) {
++		for_each_netdev(loop_net, loop_dev) {
++			struct macsec_dev *priv;
++
++			if (!netif_is_macsec(loop_dev))
++				continue;
++
++			priv = macsec_priv(loop_dev);
++
++			if (priv->real_dev == macsec->real_dev &&
++			    priv->offload != MACSEC_OFFLOAD_OFF)
++				return -EBUSY;
++		}
++	}
++
++skip_limitation:
++	/* Check if the net device is busy. */
++	if (netif_running(dev))
++		return -EBUSY;
++
++	rtnl_lock();
++
++	prev_offload = macsec->offload;
++	macsec->offload = offload;
++
++	/* Check if the device already has rules configured: we do not support
++	 * rules migration.
++	 */
++	if (macsec_is_configured(macsec)) {
++		ret = -EBUSY;
++		goto rollback;
++	}
++
++	ops = __macsec_get_ops(offload == MACSEC_OFFLOAD_OFF ? prev_offload : offload,
++			       macsec, &ctx);
++	if (!ops) {
++		ret = -EOPNOTSUPP;
++		goto rollback;
++	}
++
++	if (prev_offload == MACSEC_OFFLOAD_OFF)
++		func = ops->mdo_add_secy;
++	else
++		func = ops->mdo_del_secy;
++
++	ctx.secy = &macsec->secy;
++	ret = macsec_offload(func, &ctx);
++	if (ret)
++		goto rollback;
++
++	rtnl_unlock();
++	return 0;
++
++rollback:
++	macsec->offload = prev_offload;
++
++	rtnl_unlock();
++	return ret;
++}
++
+ static int copy_tx_sa_stats(struct sk_buff *skb,
+ 			    struct macsec_tx_sa_stats __percpu *pstats)
+ {
+@@ -2590,12 +2715,13 @@ static noinline_for_stack int
+ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 	  struct sk_buff *skb, struct netlink_callback *cb)
+ {
+-	struct macsec_rx_sc *rx_sc;
++	struct macsec_dev *macsec = netdev_priv(dev);
+ 	struct macsec_tx_sc *tx_sc = &secy->tx_sc;
+ 	struct nlattr *txsa_list, *rxsc_list;
+-	int i, j;
+-	void *hdr;
++	struct macsec_rx_sc *rx_sc;
+ 	struct nlattr *attr;
++	void *hdr;
++	int i, j;
+ 
+ 	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
+ 			  &macsec_fam, NLM_F_MULTI, MACSEC_CMD_GET_TXSC);
+@@ -2607,6 +2733,13 @@ dump_secy(struct macsec_secy *secy, struct net_device *dev,
+ 	if (nla_put_u32(skb, MACSEC_ATTR_IFINDEX, dev->ifindex))
+ 		goto nla_put_failure;
+ 
++	attr = nla_nest_start_noflag(skb, MACSEC_ATTR_OFFLOAD);
++	if (!attr)
++		goto nla_put_failure;
++	if (nla_put_u8(skb, MACSEC_OFFLOAD_ATTR_TYPE, macsec->offload))
++		goto nla_put_failure;
++	nla_nest_end(skb, attr);
++
+ 	if (nla_put_secy(secy, skb))
+ 		goto nla_put_failure;
+ 
+@@ -2872,6 +3005,12 @@ static const struct genl_ops macsec_genl_ops[] = {
+ 		.doit = macsec_upd_rxsa,
+ 		.flags = GENL_ADMIN_PERM,
+ 	},
++	{
++		.cmd = MACSEC_CMD_UPD_OFFLOAD,
++		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
++		.doit = macsec_upd_offload,
++		.flags = GENL_ADMIN_PERM,
++	},
+ };
+ 
+ static struct genl_family macsec_fam __ro_after_init = {
+diff --git a/include/uapi/linux/if_macsec.h b/include/uapi/linux/if_macsec.h
+index 98e4d5d7c45ca..1d63c43c38cca 100644
+--- a/include/uapi/linux/if_macsec.h
++++ b/include/uapi/linux/if_macsec.h
+@@ -45,6 +45,7 @@ enum macsec_attrs {
+ 	MACSEC_ATTR_RXSC_LIST,   /* dump, nested, macsec_rxsc_attrs for each RXSC */
+ 	MACSEC_ATTR_TXSC_STATS,  /* dump, nested, macsec_txsc_stats_attr */
+ 	MACSEC_ATTR_SECY_STATS,  /* dump, nested, macsec_secy_stats_attr */
++	MACSEC_ATTR_OFFLOAD,     /* config, nested, macsec_offload_attrs */
+ 	__MACSEC_ATTR_END,
+ 	NUM_MACSEC_ATTR = __MACSEC_ATTR_END,
+ 	MACSEC_ATTR_MAX = __MACSEC_ATTR_END - 1,
+@@ -97,6 +98,15 @@ enum macsec_sa_attrs {
+ 	MACSEC_SA_ATTR_MAX = __MACSEC_SA_ATTR_END - 1,
+ };
+ 
++enum macsec_offload_attrs {
++	MACSEC_OFFLOAD_ATTR_UNSPEC,
++	MACSEC_OFFLOAD_ATTR_TYPE, /* config/dump, u8 0..2 */
++	MACSEC_OFFLOAD_ATTR_PAD,
++	__MACSEC_OFFLOAD_ATTR_END,
++	NUM_MACSEC_OFFLOAD_ATTR = __MACSEC_OFFLOAD_ATTR_END,
++	MACSEC_OFFLOAD_ATTR_MAX = __MACSEC_OFFLOAD_ATTR_END - 1,
++};
++
+ enum macsec_nl_commands {
+ 	MACSEC_CMD_GET_TXSC,
+ 	MACSEC_CMD_ADD_RXSC,
+@@ -108,6 +118,7 @@ enum macsec_nl_commands {
+ 	MACSEC_CMD_ADD_RXSA,
+ 	MACSEC_CMD_DEL_RXSA,
+ 	MACSEC_CMD_UPD_RXSA,
++	MACSEC_CMD_UPD_OFFLOAD,
+ };
+ 
+ /* u64 per-RXSC stats */
+-- 
+cgit 1.2.3-1.el7
+