]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/tipc/socket.c
Merge remote-tracking branch 'asoc/fix/samsung' into asoc-linus
[karo-tx-linux.git] / net / tipc / socket.c
index 515ce38e4f4c7286023f32f4c8c692af2787ec80..ce8249c768271b9f778df694261d09a6845c5f05 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/socket.c: TIPC socket API
  *
  * Copyright (c) 2001-2007, 2012 Ericsson AB
- * Copyright (c) 2004-2008, 2010-2012, Wind River Systems
+ * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,8 +43,6 @@
 #define SS_LISTENING   -1      /* socket is listening */
 #define SS_READY       -2      /* socket is connectionless */
 
-#define CONN_OVERLOAD_LIMIT    ((TIPC_FLOW_CONTROL_WIN * 2 + 1) * \
-                               SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
 #define CONN_TIMEOUT_DEFAULT   8000    /* default connect timeout = 8s */
 
 struct tipc_sock {
@@ -65,12 +63,15 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf);
 static void wakeupdispatch(struct tipc_port *tport);
 static void tipc_data_ready(struct sock *sk, int len);
 static void tipc_write_space(struct sock *sk);
+static int release(struct socket *sock);
+static int accept(struct socket *sock, struct socket *new_sock, int flags);
 
 static const struct proto_ops packet_ops;
 static const struct proto_ops stream_ops;
 static const struct proto_ops msg_ops;
 
 static struct proto tipc_proto;
+static struct proto tipc_proto_kern;
 
 static int sockets_enabled;
 
@@ -143,7 +144,7 @@ static void reject_rx_queue(struct sock *sk)
 }
 
 /**
- * tipc_create - create a TIPC socket
+ * tipc_sk_create - create a TIPC socket
  * @net: network namespace (must be default network)
  * @sock: pre-allocated socket structure
  * @protocol: protocol indicator (must be 0)
@@ -154,8 +155,8 @@ static void reject_rx_queue(struct sock *sk)
  *
  * Returns 0 on success, errno otherwise
  */
-static int tipc_create(struct net *net, struct socket *sock, int protocol,
-                      int kern)
+static int tipc_sk_create(struct net *net, struct socket *sock, int protocol,
+                         int kern)
 {
        const struct proto_ops *ops;
        socket_state state;
@@ -185,13 +186,17 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol,
        }
 
        /* Allocate socket's protocol area */
-       sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto);
+       if (!kern)
+               sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto);
+       else
+               sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto_kern);
+
        if (sk == NULL)
                return -ENOMEM;
 
        /* Allocate TIPC port for socket to use */
-       tp_ptr = tipc_createport_raw(sk, &dispatch, &wakeupdispatch,
-                                    TIPC_LOW_IMPORTANCE);
+       tp_ptr = tipc_createport(sk, &dispatch, &wakeupdispatch,
+                                TIPC_LOW_IMPORTANCE);
        if (unlikely(!tp_ptr)) {
                sk_free(sk);
                return -ENOMEM;
@@ -203,6 +208,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol,
 
        sock_init_data(sock, sk);
        sk->sk_backlog_rcv = backlog_rcv;
+       sk->sk_rcvbuf = sysctl_tipc_rmem[1];
        sk->sk_data_ready = tipc_data_ready;
        sk->sk_write_space = tipc_write_space;
        tipc_sk(sk)->p = tp_ptr;
@@ -219,6 +225,78 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol,
        return 0;
 }
 
+/**
+ * tipc_sock_create_local - create TIPC socket from inside TIPC module
+ * @type: socket type - SOCK_RDM or SOCK_SEQPACKET
+ *
+ * We cannot use sock_creat_kern here because it bumps module user count.
+ * Since socket owner and creator is the same module we must make sure
+ * that module count remains zero for module local sockets, otherwise
+ * we cannot do rmmod.
+ *
+ * Returns 0 on success, errno otherwise
+ */
+int tipc_sock_create_local(int type, struct socket **res)
+{
+       int rc;
+       struct sock *sk;
+
+       rc = sock_create_lite(AF_TIPC, type, 0, res);
+       if (rc < 0) {
+               pr_err("Failed to create kernel socket\n");
+               return rc;
+       }
+       tipc_sk_create(&init_net, *res, 0, 1);
+
+       sk = (*res)->sk;
+
+       return 0;
+}
+
+/**
+ * tipc_sock_release_local - release socket created by tipc_sock_create_local
+ * @sock: the socket to be released.
+ *
+ * Module reference count is not incremented when such sockets are created,
+ * so we must keep it from being decremented when they are released.
+ */
+void tipc_sock_release_local(struct socket *sock)
+{
+       release(sock);
+       sock->ops = NULL;
+       sock_release(sock);
+}
+
+/**
+ * tipc_sock_accept_local - accept a connection on a socket created
+ * with tipc_sock_create_local. Use this function to avoid that
+ * module reference count is inadvertently incremented.
+ *
+ * @sock:    the accepting socket
+ * @newsock: reference to the new socket to be created
+ * @flags:   socket flags
+ */
+
+int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
+                          int flags)
+{
+       struct sock *sk = sock->sk;
+       int ret;
+
+       ret = sock_create_lite(sk->sk_family, sk->sk_type,
+                              sk->sk_protocol, newsock);
+       if (ret < 0)
+               return ret;
+
+       ret = accept(sock, *newsock, flags);
+       if (ret < 0) {
+               sock_release(*newsock);
+               return ret;
+       }
+       (*newsock)->ops = sock->ops;
+       return ret;
+}
+
 /**
  * release - destroy a TIPC socket
  * @sock: socket to destroy
@@ -324,7 +402,9 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len)
        else if (addr->addrtype != TIPC_ADDR_NAMESEQ)
                return -EAFNOSUPPORT;
 
-       if (addr->addr.nameseq.type < TIPC_RESERVED_TYPES)
+       if ((addr->addr.nameseq.type < TIPC_RESERVED_TYPES) &&
+           (addr->addr.nameseq.type != TIPC_TOP_SRV) &&
+           (addr->addr.nameseq.type != TIPC_CFG_SRV))
                return -EACCES;
 
        return (addr->scope > 0) ?
@@ -519,8 +599,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
                        res = -EISCONN;
                        goto exit;
                }
-               if ((tport->published) ||
-                   ((sock->type == SOCK_STREAM) && (total_len != 0))) {
+               if (tport->published) {
                        res = -EOPNOTSUPP;
                        goto exit;
                }
@@ -810,7 +889,7 @@ static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
  * Returns 0 if successful, otherwise errno
  */
 static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
-                               struct tipc_port *tport)
+                        struct tipc_port *tport)
 {
        u32 anc_data[3];
        u32 err;
@@ -1011,8 +1090,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
 
        lock_sock(sk);
 
-       if (unlikely((sock->state == SS_UNCONNECTED) ||
-                    (sock->state == SS_CONNECTING))) {
+       if (unlikely((sock->state == SS_UNCONNECTED))) {
                res = -ENOTCONN;
                goto exit;
        }
@@ -1233,10 +1311,10 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)
  * For all connectionless messages, by default new queue limits are
  * as belows:
  *
- * TIPC_LOW_IMPORTANCE       (5MB)
- * TIPC_MEDIUM_IMPORTANCE    (10MB)
- * TIPC_HIGH_IMPORTANCE      (20MB)
- * TIPC_CRITICAL_IMPORTANCE  (40MB)
+ * TIPC_LOW_IMPORTANCE       (MB)
+ * TIPC_MEDIUM_IMPORTANCE    (MB)
+ * TIPC_HIGH_IMPORTANCE      (16 MB)
+ * TIPC_CRITICAL_IMPORTANCE  (32 MB)
  *
  * Returns overload limit according to corresponding message importance
  */
@@ -1246,9 +1324,10 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf)
        unsigned int limit;
 
        if (msg_connected(msg))
-               limit = CONN_OVERLOAD_LIMIT;
+               limit = sysctl_tipc_rmem[2];
        else
-               limit = sk->sk_rcvbuf << (msg_importance(msg) + 5);
+               limit = sk->sk_rcvbuf >> TIPC_CRITICAL_IMPORTANCE <<
+                       msg_importance(msg);
        return limit;
 }
 
@@ -1327,7 +1406,7 @@ static int backlog_rcv(struct sock *sk, struct sk_buff *buf)
  */
 static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
 {
-       struct sock *sk = (struct sock *)tport->usr_handle;
+       struct sock *sk = tport->sk;
        u32 res;
 
        /*
@@ -1358,7 +1437,7 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
  */
 static void wakeupdispatch(struct tipc_port *tport)
 {
-       struct sock *sk = (struct sock *)tport->usr_handle;
+       struct sock *sk = tport->sk;
 
        sk->sk_write_space(sk);
 }
@@ -1531,7 +1610,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)
 
        buf = skb_peek(&sk->sk_receive_queue);
 
-       res = tipc_create(sock_net(sock->sk), new_sock, 0, 0);
+       res = tipc_sk_create(sock_net(sock->sk), new_sock, 0, 1);
        if (res)
                goto exit;
 
@@ -1657,8 +1736,8 @@ restart:
  *
  * Returns 0 on success, errno otherwise
  */
-static int setsockopt(struct socket *sock,
-                     int lvl, int opt, char __user *ov, unsigned int ol)
+static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov,
+                     unsigned int ol)
 {
        struct sock *sk = sock->sk;
        struct tipc_port *tport = tipc_sk_port(sk);
@@ -1716,8 +1795,8 @@ static int setsockopt(struct socket *sock,
  *
  * Returns 0 on success, errno otherwise
  */
-static int getsockopt(struct socket *sock,
-                     int lvl, int opt, char __user *ov, int __user *ol)
+static int getsockopt(struct socket *sock, int lvl, int opt, char __user *ov,
+                     int __user *ol)
 {
        struct sock *sk = sock->sk;
        struct tipc_port *tport = tipc_sk_port(sk);
@@ -1841,13 +1920,20 @@ static const struct proto_ops stream_ops = {
 static const struct net_proto_family tipc_family_ops = {
        .owner          = THIS_MODULE,
        .family         = AF_TIPC,
-       .create         = tipc_create
+       .create         = tipc_sk_create
 };
 
 static struct proto tipc_proto = {
        .name           = "TIPC",
        .owner          = THIS_MODULE,
-       .obj_size       = sizeof(struct tipc_sock)
+       .obj_size       = sizeof(struct tipc_sock),
+       .sysctl_rmem    = sysctl_tipc_rmem
+};
+
+static struct proto tipc_proto_kern = {
+       .name           = "TIPC",
+       .obj_size       = sizeof(struct tipc_sock),
+       .sysctl_rmem    = sysctl_tipc_rmem
 };
 
 /**