net: socket: Added notifier chains for socket administrative functions
Allows other areas in the kernel to register notifier callbacks which
get invoked whenever something performs an administrative action on a
socket. This patch adds hooks in socket(), bind(), listen(), accept(),
shutdown().
CRs-Fixed: 626021
Change-Id: I4ae99cb2206d7c4eddba69757335c18d10143045
Signed-off-by: Devi Sandeep Endluri V V <dendluri@codeaurora.org>
Acked-by: Manoj Basapathi <manojbm@qti.qualcomm.com>
diff --git a/net/socket.c b/net/socket.c
index bd9679f..539755b 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -117,6 +117,8 @@
static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to);
static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from);
+static BLOCKING_NOTIFIER_HEAD(sockev_notifier_list);
+
static int sock_mmap(struct file *file, struct vm_area_struct *vma);
static int sock_close(struct inode *inode, struct file *file);
@@ -171,6 +173,14 @@
static DEFINE_PER_CPU(int, sockets_in_use);
/*
+ * Socket Event framework helpers
+ */
+static void sockev_notify(unsigned long event, struct socket *sk)
+{
+ blocking_notifier_call_chain(&sockev_notifier_list, event, sk);
+}
+
+/**
* Support routines.
* Move socket addresses back and forth across the kernel/user
* divide and look after the messy bits.
@@ -1255,6 +1265,9 @@
if (retval < 0)
goto out;
+ if (retval == 0)
+ sockev_notify(SOCKEV_SOCKET, sock);
+
retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
if (retval < 0)
goto out_release;
@@ -1400,6 +1413,8 @@
&address, addrlen);
}
fput_light(sock->file, fput_needed);
+ if (!err)
+ sockev_notify(SOCKEV_BIND, sock);
}
return err;
}
@@ -1427,6 +1442,8 @@
err = sock->ops->listen(sock, backlog);
fput_light(sock->file, fput_needed);
+ if (!err)
+ sockev_notify(SOCKEV_LISTEN, sock);
}
return err;
}
@@ -1513,7 +1530,8 @@
fd_install(newfd, newfile);
err = newfd;
-
+ if (!err)
+ sockev_notify(SOCKEV_ACCEPT, sock);
out_put:
fput_light(sock->file, fput_needed);
out:
@@ -1563,6 +1581,8 @@
err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen,
sock->file->f_flags);
+ if (!err)
+ sockev_notify(SOCKEV_CONNECT, sock);
out_put:
fput_light(sock->file, fput_needed);
out:
@@ -1823,6 +1843,7 @@
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (sock != NULL) {
+ sockev_notify(SOCKEV_SHUTDOWN, sock);
err = security_socket_shutdown(sock, how);
if (!err)
err = sock->ops->shutdown(sock, how);
@@ -3340,3 +3361,15 @@
return sock->ops->shutdown(sock, how);
}
EXPORT_SYMBOL(kernel_sock_shutdown);
+
+int sockev_register_notify(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&sockev_notifier_list, nb);
+}
+EXPORT_SYMBOL(sockev_register_notify);
+
+int sockev_unregister_notify(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&sockev_notifier_list, nb);
+}
+EXPORT_SYMBOL(sockev_unregister_notify);