net: sockev: Initial Commit

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:  626021
Change-Id: Id5c6808d972b69f5f065d7fba9094e75c6ad0b2c
Signed-off-by: Harout Hedeshian <harouth@codeaurora.org>
This commit is contained in:
Harout Hedeshian 2014-03-04 09:16:53 -07:00 committed by Gerrit - the friendly Code Review server
parent 9a248766f6
commit c17bbe2703
6 changed files with 182 additions and 1 deletions

View File

@ -399,6 +399,7 @@ header-y += signalfd.h
header-y += snmp.h
header-y += sock_diag.h
header-y += socket.h
header-y += sockev.h
header-y += sockios.h
header-y += som.h
header-y += sonet.h

View File

@ -26,7 +26,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

View File

@ -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_ */

View File

@ -274,6 +274,15 @@ config BPF_JIT
packet sniffing (libpcap/tcpdump). Note : Admin should enable
this feature changing /proc/sys/net/core/bpf_jit_enable
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

View File

@ -22,3 +22,4 @@ obj-$(CONFIG_TRACEPOINTS) += net-traces.o
obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o
obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o
obj-$(CONFIG_NETPRIO_CGROUP) += netprio_cgroup.o
obj-$(CONFIG_SOCKEV_NLMCAST) += sockev_nlmcast.o

139
net/core/sockev_nlmcast.c Normal file
View File

@ -0,0 +1,139 @@
/*
* Copyright (c) 2014, 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, "UNKOWN", 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 == NULL) || (sock == NULL) || (sock->sk == NULL))
goto done;
skb = nlmsg_new(sizeof(struct sknlsockevmsg), GFP_KERNEL);
if (skb == NULL)
goto done;
nlh = nlmsg_put(skb, 0, 0, event, sizeof(struct sknlsockevmsg), 0);
if (nlh == NULL) {
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");