lkml.org 
[lkml]   [2010]   [Sep]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH 2/5] AF_UNIX: enable/disable multicast with getsockopt/setsockopt
Date
Multicast can be enabled or disabled after a socket is allocated but this
cannot be changed once the socket is bound or connected.

Userspace applications can enable multicast on an Unix stream socket:
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
#define UNIX_MULTICAST 1
val = 1;
len = sizeof(val);
ret = setsockopt(sockfd, 0, UNIX_MULTICAST, &val, len);

Signed-off-by: Alban Crequy <alban.crequy@collabora.co.uk>
---
include/net/af_unix.h | 4 +++
net/unix/af_unix.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 20725e2..4c77c69 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -40,6 +40,9 @@ struct unix_skb_parms {
spin_lock_nested(&unix_sk(s)->lock, \
SINGLE_DEPTH_NESTING)

+/* UNIX socket options */
+#define UNIX_MULTICAST 1 /* Enable multicast Unix sockets */
+
#ifdef __KERNEL__
/* The AF_UNIX socket */
struct unix_sock {
@@ -56,6 +59,7 @@ struct unix_sock {
spinlock_t lock;
unsigned int gc_candidate : 1;
unsigned int gc_maybe_cycle : 1;
+ unsigned int multicast : 1;
struct socket_wq peer_wq;
};
#define unix_sk(__sk) ((struct unix_sock *)__sk)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 47d9f77..c766e88 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1501,13 +1501,66 @@ out:
static int unix_stream_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
{
- return -EOPNOTSUPP;
+ struct unix_sock *u = unix_sk(sock->sk);
+ int val;
+ int err = 0;
+
+ if (optlen < sizeof(int))
+ return -EINVAL;
+
+ if (get_user(val, (int __user *)optval))
+ return -EFAULT;
+
+ switch (optname) {
+ case UNIX_MULTICAST:
+ /* Multicast feature can only be changed when the socket is
+ * not used yet */
+ if (u->addr || sock->sk->sk_state != TCP_CLOSE)
+ return -EINVAL;
+
+ if (val != 0) {
+ u->multicast = 1;
+ } else {
+ u->multicast = 0;
+ }
+ break;
+
+ default:
+ err = -ENOPROTOOPT;
+ break;
+ }
+
+ return err;
}

int unix_stream_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
- return -EOPNOTSUPP;
+ struct unix_sock *u = unix_sk(sock->sk);
+ int val, len;
+
+ if (get_user(len, optlen))
+ return -EFAULT;
+
+ len = min_t(unsigned int, len, sizeof(int));
+
+ if (len < 0)
+ return -EINVAL;
+
+ switch (optname) {
+ case UNIX_MULTICAST:
+ val = u->multicast;
+ break;
+
+ default:
+ return -ENOPROTOOPT;
+ }
+
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, &val, len))
+ return -EFAULT;
+ return 0;
}


--
1.7.1


\
 
 \ /
  Last update: 2010-09-27 20:09    [W:0.782 / U:0.272 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site