usb/gadget: Replace the old USB audio FU definitions in f_audio.c
[safe/jmp/linux-2.6] / net / rxrpc / af_rxrpc.c
index bfa8822..0b9bb20 100644 (file)
 
 #include <linux/module.h>
 #include <linux/net.h>
+#include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
+#include <linux/key-type.h>
+#include <net/net_namespace.h>
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
@@ -25,7 +28,7 @@ MODULE_ALIAS_NETPROTO(PF_RXRPC);
 
 unsigned rxrpc_debug; // = RXRPC_DEBUG_KPROTO;
 module_param_named(debug, rxrpc_debug, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(rxrpc_debug, "RxRPC debugging mask");
+MODULE_PARM_DESC(debug, "RxRPC debugging mask");
 
 static int sysctl_rxrpc_max_qlen __read_mostly = 10;
 
@@ -41,6 +44,8 @@ atomic_t rxrpc_debug_id;
 /* count of skbs currently in use */
 atomic_t rxrpc_n_skbs;
 
+struct workqueue_struct *rxrpc_workqueue;
+
 static void rxrpc_sock_destructor(struct sock *);
 
 /*
@@ -57,13 +62,15 @@ static inline int rxrpc_writable(struct sock *sk)
 static void rxrpc_write_space(struct sock *sk)
 {
        _enter("%p", sk);
-       read_lock(&sk->sk_callback_lock);
+       rcu_read_lock();
        if (rxrpc_writable(sk)) {
-               if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-                       wake_up_interruptible(sk->sk_sleep);
-               sk_wake_async(sk, 2, POLL_OUT);
+               struct socket_wq *wq = rcu_dereference(sk->sk_wq);
+
+               if (wq_has_sleeper(wq))
+                       wake_up_interruptible(&wq->wait);
+               sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
        }
-       read_unlock(&sk->sk_callback_lock);
+       rcu_read_unlock();
 }
 
 /*
@@ -92,9 +99,9 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
 
        switch (srx->transport.family) {
        case AF_INET:
-               _debug("INET: %x @ %u.%u.%u.%u",
+               _debug("INET: %x @ %pI4",
                       ntohs(srx->transport.sin.sin_port),
-                      NIPQUAD(srx->transport.sin.sin_addr));
+                      &srx->transport.sin.sin_addr);
                if (srx->transport_len > 8)
                        memset((void *)&srx->transport + 8, 0,
                               srx->transport_len - 8);
@@ -214,7 +221,8 @@ static int rxrpc_listen(struct socket *sock, int backlog)
  */
 static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock,
                                                       struct sockaddr *addr,
-                                                      int addr_len, int flags)
+                                                      int addr_len, int flags,
+                                                      gfp_t gfp)
 {
        struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) addr;
        struct rxrpc_transport *trans;
@@ -232,17 +240,130 @@ static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock,
                return ERR_PTR(-EAFNOSUPPORT);
 
        /* find a remote transport endpoint from the local one */
-       peer = rxrpc_get_peer(srx, GFP_KERNEL);
+       peer = rxrpc_get_peer(srx, gfp);
        if (IS_ERR(peer))
-               return ERR_PTR(PTR_ERR(peer));
+               return ERR_CAST(peer);
 
        /* find a transport */
-       trans = rxrpc_get_transport(rx->local, peer, GFP_KERNEL);
+       trans = rxrpc_get_transport(rx->local, peer, gfp);
        rxrpc_put_peer(peer);
        _leave(" = %p", trans);
        return trans;
 }
 
+/**
+ * rxrpc_kernel_begin_call - Allow a kernel service to begin a call
+ * @sock: The socket on which to make the call
+ * @srx: The address of the peer to contact (defaults to socket setting)
+ * @key: The security context to use (defaults to socket setting)
+ * @user_call_ID: The ID to use
+ *
+ * Allow a kernel service to begin a call on the nominated socket.  This just
+ * sets up all the internal tracking structures and allocates connection and
+ * call IDs as appropriate.  The call to be used is returned.
+ *
+ * The default socket destination address and security may be overridden by
+ * supplying @srx and @key.
+ */
+struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
+                                          struct sockaddr_rxrpc *srx,
+                                          struct key *key,
+                                          unsigned long user_call_ID,
+                                          gfp_t gfp)
+{
+       struct rxrpc_conn_bundle *bundle;
+       struct rxrpc_transport *trans;
+       struct rxrpc_call *call;
+       struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+       __be16 service_id;
+
+       _enter(",,%x,%lx", key_serial(key), user_call_ID);
+
+       lock_sock(&rx->sk);
+
+       if (srx) {
+               trans = rxrpc_name_to_transport(sock, (struct sockaddr *) srx,
+                                               sizeof(*srx), 0, gfp);
+               if (IS_ERR(trans)) {
+                       call = ERR_CAST(trans);
+                       trans = NULL;
+                       goto out_notrans;
+               }
+       } else {
+               trans = rx->trans;
+               if (!trans) {
+                       call = ERR_PTR(-ENOTCONN);
+                       goto out_notrans;
+               }
+               atomic_inc(&trans->usage);
+       }
+
+       service_id = rx->service_id;
+       if (srx)
+               service_id = htons(srx->srx_service);
+
+       if (!key)
+               key = rx->key;
+       if (key && !key->payload.data)
+               key = NULL; /* a no-security key */
+
+       bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp);
+       if (IS_ERR(bundle)) {
+               call = ERR_CAST(bundle);
+               goto out;
+       }
+
+       call = rxrpc_get_client_call(rx, trans, bundle, user_call_ID, true,
+                                    gfp);
+       rxrpc_put_bundle(trans, bundle);
+out:
+       rxrpc_put_transport(trans);
+out_notrans:
+       release_sock(&rx->sk);
+       _leave(" = %p", call);
+       return call;
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_begin_call);
+
+/**
+ * rxrpc_kernel_end_call - Allow a kernel service to end a call it was using
+ * @call: The call to end
+ *
+ * Allow a kernel service to end a call it was using.  The call must be
+ * complete before this is called (the call should be aborted if necessary).
+ */
+void rxrpc_kernel_end_call(struct rxrpc_call *call)
+{
+       _enter("%d{%d}", call->debug_id, atomic_read(&call->usage));
+       rxrpc_remove_user_ID(call->socket, call);
+       rxrpc_put_call(call);
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_end_call);
+
+/**
+ * rxrpc_kernel_intercept_rx_messages - Intercept received RxRPC messages
+ * @sock: The socket to intercept received messages on
+ * @interceptor: The function to pass the messages to
+ *
+ * Allow a kernel service to intercept messages heading for the Rx queue on an
+ * RxRPC socket.  They get passed to the specified function instead.
+ * @interceptor should free the socket buffers it is given.  @interceptor is
+ * called with the socket receive queue spinlock held and softirqs disabled -
+ * this ensures that the messages will be delivered in the right order.
+ */
+void rxrpc_kernel_intercept_rx_messages(struct socket *sock,
+                                       rxrpc_interceptor_t interceptor)
+{
+       struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+
+       _enter("");
+       rx->interceptor = interceptor;
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_intercept_rx_messages);
+
 /*
  * connect an RxRPC socket
  * - this just targets it at a specific destination; no actual connection
@@ -294,7 +415,8 @@ static int rxrpc_connect(struct socket *sock, struct sockaddr *addr,
                return -EBUSY; /* server sockets can't connect as well */
        }
 
-       trans = rxrpc_name_to_transport(sock, addr, addr_len, flags);
+       trans = rxrpc_name_to_transport(sock, addr, addr_len, flags,
+                                       GFP_KERNEL);
        if (IS_ERR(trans)) {
                release_sock(&rx->sk);
                _leave(" = %ld", PTR_ERR(trans));
@@ -344,7 +466,7 @@ static int rxrpc_sendmsg(struct kiocb *iocb, struct socket *sock,
        if (m->msg_name) {
                ret = -EISCONN;
                trans = rxrpc_name_to_transport(sock, m->msg_name,
-                                               m->msg_namelen, 0);
+                                               m->msg_namelen, 0, GFP_KERNEL);
                if (IS_ERR(trans)) {
                        ret = PTR_ERR(trans);
                        trans = NULL;
@@ -388,7 +510,7 @@ out:
  * set RxRPC socket options
  */
 static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
-                           char __user *optval, int optlen)
+                           char __user *optval, unsigned int optlen)
 {
        struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
        unsigned min_sec_level;
@@ -469,7 +591,7 @@ static unsigned int rxrpc_poll(struct file *file, struct socket *sock,
        unsigned int mask;
        struct sock *sk = sock->sk;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk_sleep(sk), wait);
        mask = 0;
 
        /* the socket is readable if there are any messages waiting on the Rx
@@ -489,13 +611,17 @@ static unsigned int rxrpc_poll(struct file *file, struct socket *sock,
 /*
  * create an RxRPC socket
  */
-static int rxrpc_create(struct socket *sock, int protocol)
+static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
+                       int kern)
 {
        struct rxrpc_sock *rx;
        struct sock *sk;
 
        _enter("%p,%d", sock, protocol);
 
+       if (!net_eq(net, &init_net))
+               return -EAFNOSUPPORT;
+
        /* we support transport protocol UDP only */
        if (protocol != PF_INET)
                return -EPROTONOSUPPORT;
@@ -506,7 +632,7 @@ static int rxrpc_create(struct socket *sock, int protocol)
        sock->ops = &rxrpc_rpc_ops;
        sock->state = SS_UNCONNECTED;
 
-       sk = sk_alloc(PF_RXRPC, GFP_KERNEL, &rxrpc_proto, 1);
+       sk = sk_alloc(net, PF_RXRPC, GFP_KERNEL, &rxrpc_proto);
        if (!sk)
                return -ENOMEM;
 
@@ -539,9 +665,9 @@ static void rxrpc_sock_destructor(struct sock *sk)
 
        rxrpc_purge_queue(&sk->sk_receive_queue);
 
-       BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc));
-       BUG_TRAP(sk_unhashed(sk));
-       BUG_TRAP(!sk->sk_socket);
+       WARN_ON(atomic_read(&sk->sk_wmem_alloc));
+       WARN_ON(!sk_unhashed(sk));
+       WARN_ON(sk->sk_socket);
 
        if (!sock_flag(sk, SOCK_DEAD)) {
                printk("Attempt to release alive rxrpc socket: %p\n", sk);
@@ -576,7 +702,7 @@ static int rxrpc_release_sock(struct sock *sk)
 
        /* try to flush out this socket */
        rxrpc_release_calls_on_socket(rx);
-       flush_scheduled_work();
+       flush_workqueue(rxrpc_workqueue);
        rxrpc_purge_queue(&sk->sk_receive_queue);
 
        if (rx->conn) {
@@ -655,7 +781,7 @@ static struct proto rxrpc_proto = {
        .max_header     = sizeof(struct rxrpc_header),
 };
 
-static struct net_proto_family rxrpc_family_ops = {
+static const struct net_proto_family rxrpc_family_ops = {
        .family = PF_RXRPC,
        .create = rxrpc_create,
        .owner  = THIS_MODULE,
@@ -671,44 +797,50 @@ static int __init af_rxrpc_init(void)
 
        BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof(dummy_skb->cb));
 
-       rxrpc_epoch = htonl(xtime.tv_sec);
+       rxrpc_epoch = htonl(get_seconds());
 
+       ret = -ENOMEM;
        rxrpc_call_jar = kmem_cache_create(
                "rxrpc_call_jar", sizeof(struct rxrpc_call), 0,
-               SLAB_HWCACHE_ALIGN, NULL, NULL);
+               SLAB_HWCACHE_ALIGN, NULL);
        if (!rxrpc_call_jar) {
                printk(KERN_NOTICE "RxRPC: Failed to allocate call jar\n");
-               ret = -ENOMEM;
                goto error_call_jar;
        }
 
+       rxrpc_workqueue = create_workqueue("krxrpcd");
+       if (!rxrpc_workqueue) {
+               printk(KERN_NOTICE "RxRPC: Failed to allocate work queue\n");
+               goto error_work_queue;
+       }
+
        ret = proto_register(&rxrpc_proto, 1);
-        if (ret < 0) {
-                printk(KERN_CRIT "RxRPC: Cannot register protocol\n");
+       if (ret < 0) {
+               printk(KERN_CRIT "RxRPC: Cannot register protocol\n");
                goto error_proto;
        }
 
        ret = sock_register(&rxrpc_family_ops);
        if (ret < 0) {
-                printk(KERN_CRIT "RxRPC: Cannot register socket family\n");
+               printk(KERN_CRIT "RxRPC: Cannot register socket family\n");
                goto error_sock;
        }
 
        ret = register_key_type(&key_type_rxrpc);
        if (ret < 0) {
-                printk(KERN_CRIT "RxRPC: Cannot register client key type\n");
+               printk(KERN_CRIT "RxRPC: Cannot register client key type\n");
                goto error_key_type;
        }
 
        ret = register_key_type(&key_type_rxrpc_s);
        if (ret < 0) {
-                printk(KERN_CRIT "RxRPC: Cannot register server key type\n");
+               printk(KERN_CRIT "RxRPC: Cannot register server key type\n");
                goto error_key_type_s;
        }
 
 #ifdef CONFIG_PROC_FS
-       proc_net_fops_create("rxrpc_calls", 0, &rxrpc_call_seq_fops);
-       proc_net_fops_create("rxrpc_conns", 0, &rxrpc_connection_seq_fops);
+       proc_net_fops_create(&init_net, "rxrpc_calls", 0, &rxrpc_call_seq_fops);
+       proc_net_fops_create(&init_net, "rxrpc_conns", 0, &rxrpc_connection_seq_fops);
 #endif
        return 0;
 
@@ -719,6 +851,8 @@ error_key_type:
 error_sock:
        proto_unregister(&rxrpc_proto);
 error_proto:
+       destroy_workqueue(rxrpc_workqueue);
+error_work_queue:
        kmem_cache_destroy(rxrpc_call_jar);
 error_call_jar:
        return ret;
@@ -743,9 +877,10 @@ static void __exit af_rxrpc_exit(void)
        ASSERTCMP(atomic_read(&rxrpc_n_skbs), ==, 0);
 
        _debug("flush scheduled work");
-       flush_scheduled_work();
-       proc_net_remove("rxrpc_conns");
-       proc_net_remove("rxrpc_calls");
+       flush_workqueue(rxrpc_workqueue);
+       proc_net_remove(&init_net, "rxrpc_conns");
+       proc_net_remove(&init_net, "rxrpc_calls");
+       destroy_workqueue(rxrpc_workqueue);
        kmem_cache_destroy(rxrpc_call_jar);
        _leave("");
 }