[qca-nss-clients] Add Multicast support for l2tpv2 netlink module

Change-Id: If4d9f0d602c3e521e2bfb37007fba168ca08c1c7
Signed-off-by: Wayne Tan <wtan@codeaurora.org>
diff --git a/netlink/Makefile b/netlink/Makefile
index 69affb7..40fff0f 100644
--- a/netlink/Makefile
+++ b/netlink/Makefile
@@ -21,6 +21,7 @@
 ccflags-y += -DCONFIG_NSS_NLLSO_RX=1
 ccflags-y += -DCONFIG_NSS_NLMAP_T=1
 ccflags-y += -DCONFIG_NSS_NLPPPOE=1
+ccflags-y += -DCONFIG_NSS_NLL2TPV2=1
 
 qca-nss-netlink-objs := nss_nl.o
 qca-nss-netlink-objs += nss_nlgre_redir_family.o
@@ -44,6 +45,7 @@
 qca-nss-netlink-objs += nss_nllso_rx.o
 qca-nss-netlink-objs += nss_nlmap_t.o
 qca-nss-netlink-objs += nss_nlpppoe.o
+qca-nss-netlink-objs += nss_nll2tpv2.o
 
 CAPWAP_ENABLED:=CONFIG_PACKAGE_kmod-qca-nss-drv-capwapmgr=y
 CAPWAP_CONFIG:=$(shell  grep $(CAPWAP_ENABLED) $(TOPDIR)/.config)
diff --git a/netlink/include/nss_nlcmn_if.h b/netlink/include/nss_nlcmn_if.h
index f923eb9..071f060 100644
--- a/netlink/include/nss_nlcmn_if.h
+++ b/netlink/include/nss_nlcmn_if.h
@@ -51,6 +51,7 @@
 	NSS_NLCMN_SUBSYS_IPV4_REASM,
 	NSS_NLCMN_SUBSYS_IPV6,
 	NSS_NLCMN_SUBSYS_IPV6_REASM,
+	NSS_NLCMN_SUBSYS_L2TPV2,
 	NSS_NLCMN_SUBSYS_LSO_RX,
 	NSS_NLCMN_SUBSYS_MAP_T,
 	NSS_NLCMN_SUBSYS_N2H,
diff --git a/netlink/include/nss_nll2tpv2_if.h b/netlink/include/nss_nll2tpv2_if.h
new file mode 100644
index 0000000..8c005f0
--- /dev/null
+++ b/netlink/include/nss_nll2tpv2_if.h
@@ -0,0 +1,32 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+/*
+ * @file nss_nll2tpv2_if.h
+ *	NSS Netlink l2tpv2 headers
+ */
+#ifndef __NSS_NLL2TPV2_IF_H
+#define __NSS_NLL2TPV2_IF_H
+
+/**
+ * l2tpv2 forwarding Family
+ */
+#define NSS_NLL2TPV2_FAMILY "nss_nll2tpv2"
+#define NSS_NLL2TPV2_MCAST_GRP "nss_nll2tpv2_mc"
+
+#endif /* __NSS_NLL2TPV2_IF_H */
diff --git a/netlink/nss_nl.c b/netlink/nss_nl.c
index a751008..d8ad183 100644
--- a/netlink/nss_nl.c
+++ b/netlink/nss_nl.c
@@ -74,6 +74,8 @@
 #include "nss_nlmap_t_if.h"
 #include "nss_nlpppoe.h"
 #include "nss_nlpppoe_if.h"
+#include "nss_nll2tpv2.h"
+#include "nss_nll2tpv2_if.h"
 #if defined (CONFIG_NSS_NLCRYPTO)
 #include "nss_nlcrypto_if.h"
 #else
@@ -291,6 +293,15 @@
 		.exit = NSS_NLPPPOE_EXIT,		/* exit */
 		.valid = CONFIG_NSS_NLPPPOE		/* 1 or 0 */
 	},
+	{
+		/*
+		 * NSS_NLL2TPV2
+		 */
+		.name = NSS_NLL2TPV2_FAMILY,		/* l2tpv2 */
+		.entry = NSS_NLL2TPV2_INIT,		/* init */
+		.exit = NSS_NLL2TPV2_EXIT,		/* exit */
+		.valid = CONFIG_NSS_NLL2TPV2		/* 1 or 0 */
+	},
 };
 
 #define NSS_NL_FAMILY_HANDLER_SZ ARRAY_SIZE(family_handlers)
diff --git a/netlink/nss_nll2tpv2.c b/netlink/nss_nll2tpv2.c
new file mode 100644
index 0000000..c4c04f8
--- /dev/null
+++ b/netlink/nss_nll2tpv2.c
@@ -0,0 +1,173 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+/*
+ * nss_nll2tpv2.c
+ *	NSS Netlink l2tpv2 Handler
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/netlink.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/notifier.h>
+
+#include <net/genetlink.h>
+#include <net/sock.h>
+
+#include <nss_api_if.h>
+#include <nss_cmn.h>
+#include <nss_nl_if.h>
+#include "nss_nl.h"
+#include "nss_nlcmn_if.h"
+#include "nss_nll2tpv2_if.h"
+#include "nss_l2tpv2.h"
+
+/*
+ * prototypes
+ */
+static int nss_nll2tpv2_ops_get_stats(struct sk_buff *skb, struct genl_info *info);
+static int nss_nll2tpv2_process_notify(struct notifier_block *nb, unsigned long val, void *data);
+
+/*
+ * l2tpv2 family definition
+ */
+static struct genl_family nss_nll2tpv2_family = {
+	.id = GENL_ID_GENERATE,						/* Auto generate ID */
+	.name = NSS_NLL2TPV2_FAMILY,					/* family name string */
+	.hdrsize = sizeof(struct nss_l2tpv2_stats_notification),	/* NSS NETLINK l2tpv2 stats */
+	.version = NSS_NL_VER,						/* Set it to NSS_NLL2TPV2 version */
+	.maxattr = NSS_STATS_EVENT_MAX,					/* maximum commands supported */
+	.netnsok = true,
+	.pre_doit = NULL,
+	.post_doit = NULL,
+};
+
+/*
+ * multicast group for sending message status & events
+ */
+static const struct genl_multicast_group nss_nll2tpv2_mcgrp[] = {
+	{.name = NSS_NLL2TPV2_MCAST_GRP},
+};
+
+/*
+ * operation table called by the generic netlink layer based on the command
+ */
+static struct genl_ops nss_nll2tpv2_ops[] = {
+	{.cmd = NSS_STATS_EVENT_NOTIFY, .doit = nss_nll2tpv2_ops_get_stats},
+};
+
+/*
+ * device call back handler for l2tpv2 from NSS
+ */
+static struct notifier_block nss_l2tpv2_stats_notifier_nb = {
+	.notifier_call = nss_nll2tpv2_process_notify,
+};
+
+/*
+ * nss_nll2tpv2_ops_get_stats()
+ *	get stats handler
+ */
+static int nss_nll2tpv2_ops_get_stats(struct sk_buff *skb, struct genl_info *info)
+{
+	return 0;
+}
+
+/*
+ * nss_nll2tpv2_process_notify()
+ *	process notification messages from NSS
+ */
+static int nss_nll2tpv2_process_notify(struct notifier_block *nb, unsigned long val, void *data)
+{
+	struct sk_buff *skb;
+	struct nss_l2tpv2_stats_notification *nss_stats, *nl_stats;
+
+	nss_stats = (struct nss_l2tpv2_stats_notification *)data;
+	skb = nss_nl_new_msg(&nss_nll2tpv2_family, NSS_NLCMN_SUBSYS_L2TPV2);
+	if (!skb) {
+		nss_nl_error("unable to allocate NSS_NLL2TPV2 event\n");
+		return NOTIFY_DONE;
+	}
+
+	nl_stats = nss_nl_get_data(skb);
+	memcpy(nl_stats, nss_stats, sizeof(struct nss_l2tpv2_stats_notification));
+	nss_nl_mcast_event(&nss_nll2tpv2_family, skb);
+
+	return NOTIFY_DONE;
+}
+
+/*
+ * nss_nll2tpv2_init()
+ *	handler init
+ */
+bool nss_nll2tpv2_init(void)
+{
+	int error,ret;
+
+	nss_nl_info_always("Init NSS netlink l2tpv2 handler\n");
+
+	/*
+	 * register NETLINK ops with the family
+	 */
+	error = genl_register_family_with_ops_groups(&nss_nll2tpv2_family, nss_nll2tpv2_ops, nss_nll2tpv2_mcgrp);
+	if (error) {
+		nss_nl_info_always("Error: unable to register l2tpv2 family\n");
+		return false;
+	}
+
+	/*
+	 * register device call back handler for l2tpv2 from NSS
+	 */
+	ret = nss_l2tpv2_stats_register_notifier(&nss_l2tpv2_stats_notifier_nb);
+	if (ret) {
+		nss_nl_info_always("Error: retreiving the NSS Context\n");
+		genl_unregister_family(&nss_nll2tpv2_family);
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * nss_nll2tpv2_exit()
+ *	handler exit
+ */
+bool nss_nll2tpv2_exit(void)
+{
+	int error;
+
+	nss_nl_info_always("Exit NSS netlink l2tpv2 handler\n");
+
+	/*
+	 * Unregister the device callback handler for l2tpv2
+	 */
+	nss_l2tpv2_stats_unregister_notifier(&nss_l2tpv2_stats_notifier_nb);
+
+	/*
+	 * unregister the ops family
+	 */
+	error = genl_unregister_family(&nss_nll2tpv2_family);
+	if (error) {
+		nss_nl_info_always("unable to unregister l2tpv2 NETLINK family\n");
+		return false;
+	}
+
+	return true;
+}
diff --git a/netlink/nss_nll2tpv2.h b/netlink/nss_nll2tpv2.h
new file mode 100644
index 0000000..9862b3a
--- /dev/null
+++ b/netlink/nss_nll2tpv2.h
@@ -0,0 +1,37 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+/*
+ * nss_nll2tpv2.h
+ *	NSS Netlink l2tpv2 API definitions
+ */
+#ifndef __NSS_NLL2TPV2_H
+#define __NSS_NLL2TPV2_H
+
+bool nss_nll2tpv2_init(void);
+bool nss_nll2tpv2_exit(void);
+
+#if defined(CONFIG_NSS_NLL2TPV2)
+#define NSS_NLL2TPV2_INIT nss_nll2tpv2_init
+#define NSS_NLL2TPV2_EXIT nss_nll2tpv2_exit
+#else
+#define NSS_NLL2TPV2_INIT 0
+#define NSS_NLL2TPV2_EXIT 0
+#endif /* !CONFIG_NSS_NLL2TPV2 */
+
+#endif /* __NSS_NLL2TPV2_H */