net: Add snapshot of sockev module
This is a snapshot of the sockev module taken as of msm-4.4
commit 33193859886dd87 ("net: core: Send only BIND and LISTEN events.").
Added module which subscribes to socket notifier events. Notifier events
are then converted to a multicast netlink message for user space
applications to consume.
CRs-Fixed: 1078373
Change-Id: If72b7c9a127d3861d276b681b052be3619bc6562
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 4823794..33ba430 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -428,6 +428,7 @@
header-y += snmp.h
header-y += sock_diag.h
header-y += socket.h
+header-y += sockev.h
header-y += sockios.h
header-y += sonet.h
header-y += sonypi.h
diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h
index 0dba4e4..2817ca1 100644
--- a/include/uapi/linux/netlink.h
+++ b/include/uapi/linux/netlink.h
@@ -27,7 +27,7 @@
#define NETLINK_ECRYPTFS 19
#define NETLINK_RDMA 20
#define NETLINK_CRYPTO 21 /* Crypto layer */
-
+#define NETLINK_SOCKEV 22 /* Socket Administrative Events */
#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG
#define MAX_LINKS 32
diff --git a/include/uapi/linux/sockev.h b/include/uapi/linux/sockev.h
new file mode 100644
index 0000000..b274fbc
--- /dev/null
+++ b/include/uapi/linux/sockev.h
@@ -0,0 +1,31 @@
+#ifndef _SOCKEV_H_
+#define _SOCKEV_H_
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/socket.h>
+
+enum sknetlink_groups {
+ SKNLGRP_UNICAST,
+ SKNLGRP_SOCKEV,
+ __SKNLGRP_MAX
+};
+
+#define SOCKEV_STR_MAX 32
+
+/********************************************************************
+ * Socket operation messages
+ ****/
+
+struct sknlsockevmsg {
+ __u8 event[SOCKEV_STR_MAX];
+ __u32 pid; /* (struct task_struct*)->pid */
+ __u16 skfamily; /* (struct socket*)->sk->sk_family */
+ __u8 skstate; /* (struct socket*)->sk->sk_state */
+ __u8 skprotocol; /* (struct socket*)->sk->sk_protocol */
+ __u16 sktype; /* (struct socket*)->sk->sk_type */
+ __u64 skflags; /* (struct socket*)->sk->sk_flags */
+};
+
+#endif /* _SOCKEV_H_ */
+
diff --git a/net/Kconfig b/net/Kconfig
index cd20118..d5ff4f7 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -321,6 +321,15 @@
with many clients some protection against DoS by a single (spoofed)
flow that greatly exceeds average workload.
+config SOCKEV_NLMCAST
+ bool "Enable SOCKEV Netlink Multicast"
+ default n
+ ---help---
+ Default client for SOCKEV notifier events. Sends multicast netlink
+ messages whenever the socket event notifier is invoked. Enable if
+ user space entities need to be notified of socket events without
+ having to poll /proc
+
menu "Network testing"
config NET_PKTGEN
diff --git a/net/core/Makefile b/net/core/Makefile
index d6508c2..77bb89b 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -24,6 +24,7 @@
obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o
obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o
obj-$(CONFIG_LWTUNNEL) += lwtunnel.o
+obj-$(CONFIG_SOCKEV_NLMCAST) += sockev_nlmcast.o
obj-$(CONFIG_DST_CACHE) += dst_cache.o
obj-$(CONFIG_HWBM) += hwbm.o
obj-$(CONFIG_NET_DEVLINK) += devlink.o
diff --git a/net/core/sockev_nlmcast.c b/net/core/sockev_nlmcast.c
new file mode 100644
index 0000000..04f61fc
--- /dev/null
+++ b/net/core/sockev_nlmcast.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2014-2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * Default SOCKEV client implementation
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/netlink.h>
+#include <linux/sockev.h>
+#include <net/sock.h>
+
+static int registration_status;
+static struct sock *socknlmsgsk;
+
+static void sockev_skmsg_recv(struct sk_buff *skb)
+{
+ pr_debug("%s(): Got unsolicited request\n", __func__);
+}
+
+static struct netlink_kernel_cfg nlcfg = {
+ .input = sockev_skmsg_recv
+};
+
+static void _sockev_event(unsigned long event, __u8 *evstr, int buflen)
+{
+ switch (event) {
+ case SOCKEV_SOCKET:
+ strlcpy(evstr, "SOCKEV_SOCKET", buflen);
+ break;
+ case SOCKEV_BIND:
+ strlcpy(evstr, "SOCKEV_BIND", buflen);
+ break;
+ case SOCKEV_LISTEN:
+ strlcpy(evstr, "SOCKEV_LISTEN", buflen);
+ break;
+ case SOCKEV_ACCEPT:
+ strlcpy(evstr, "SOCKEV_ACCEPT", buflen);
+ break;
+ case SOCKEV_CONNECT:
+ strlcpy(evstr, "SOCKEV_CONNECT", buflen);
+ break;
+ case SOCKEV_SHUTDOWN:
+ strlcpy(evstr, "SOCKEV_SHUTDOWN", buflen);
+ break;
+ default:
+ strlcpy(evstr, "UNKNOWN", buflen);
+ }
+}
+
+static int sockev_client_cb(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ struct sknlsockevmsg *smsg;
+ struct socket *sock;
+
+ sock = (struct socket *)data;
+ if (socknlmsgsk == 0)
+ goto done;
+ if ((!socknlmsgsk) || (!sock) || (!sock->sk))
+ goto done;
+
+ if (sock->sk->sk_family != AF_INET && sock->sk->sk_family != AF_INET6)
+ goto done;
+
+ if (event != SOCKEV_BIND && event != SOCKEV_LISTEN)
+ goto done;
+
+ skb = nlmsg_new(sizeof(struct sknlsockevmsg), GFP_KERNEL);
+ if (!skb)
+ goto done;
+
+ nlh = nlmsg_put(skb, 0, 0, event, sizeof(struct sknlsockevmsg), 0);
+ if (!nlh) {
+ kfree_skb(skb);
+ goto done;
+ }
+
+ NETLINK_CB(skb).dst_group = SKNLGRP_SOCKEV;
+
+ smsg = nlmsg_data(nlh);
+ smsg->pid = current->pid;
+ _sockev_event(event, smsg->event, sizeof(smsg->event));
+ smsg->skfamily = sock->sk->sk_family;
+ smsg->skstate = sock->sk->sk_state;
+ smsg->skprotocol = sock->sk->sk_protocol;
+ smsg->sktype = sock->sk->sk_type;
+ smsg->skflags = sock->sk->sk_flags;
+
+ nlmsg_notify(socknlmsgsk, skb, 0, SKNLGRP_SOCKEV, 0, GFP_KERNEL);
+done:
+ return 0;
+}
+
+static struct notifier_block sockev_notifier_client = {
+ .notifier_call = sockev_client_cb,
+ .next = 0,
+ .priority = 0
+};
+
+/* ***************** Startup/Shutdown *************************************** */
+
+static int __init sockev_client_init(void)
+{
+ int rc;
+
+ registration_status = 1;
+ rc = sockev_register_notify(&sockev_notifier_client);
+ if (rc != 0) {
+ registration_status = 0;
+ pr_err("%s(): Failed to register cb (%d)\n", __func__, rc);
+ }
+ socknlmsgsk = netlink_kernel_create(&init_net, NETLINK_SOCKEV, &nlcfg);
+ if (!socknlmsgsk) {
+ pr_err("%s(): Failed to initialize netlink socket\n", __func__);
+ if (registration_status)
+ sockev_unregister_notify(&sockev_notifier_client);
+ registration_status = 0;
+ }
+
+ return rc;
+}
+
+static void __exit sockev_client_exit(void)
+{
+ if (registration_status)
+ sockev_unregister_notify(&sockev_notifier_client);
+}
+
+module_init(sockev_client_init)
+module_exit(sockev_client_exit)
+MODULE_LICENSE("GPL v2");
+