NFC: Move LLCP MIU extension value to socket structure
[deliverable/linux.git] / net / nfc / llcp / sock.c
index c13e02ebdef9b08e5c995f5cbb5a671db42d8e3c..30e3cc71be7a0328626e42c3f06555cf8f989de5 100644 (file)
 #include "../nfc.h"
 #include "llcp.h"
 
+static int sock_wait_state(struct sock *sk, int state, unsigned long timeo)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int err = 0;
+
+       pr_debug("sk %p", sk);
+
+       add_wait_queue(sk_sleep(sk), &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       while (sk->sk_state != state) {
+               if (!timeo) {
+                       err = -EINPROGRESS;
+                       break;
+               }
+
+               if (signal_pending(current)) {
+                       err = sock_intr_errno(timeo);
+                       break;
+               }
+
+               release_sock(sk);
+               timeo = schedule_timeout(timeo);
+               lock_sock(sk);
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               err = sock_error(sk);
+               if (err)
+                       break;
+       }
+
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(sk_sleep(sk), &wait);
+       return err;
+}
+
 static struct proto llcp_sock_proto = {
        .name     = "NFC_LLCP",
        .owner    = THIS_MODULE,
@@ -75,7 +111,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
        }
 
        llcp_sock->dev = dev;
-       llcp_sock->local = local;
+       llcp_sock->local = nfc_llcp_local_get(local);
        llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
        llcp_sock->service_name_len = min_t(unsigned int,
                                            llcp_addr.service_name_len,
@@ -88,7 +124,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
        if (llcp_sock->ssap == LLCP_MAX_SAP)
                goto put_dev;
 
-       local->sockets[llcp_sock->ssap] = llcp_sock;
+       nfc_llcp_sock_link(&local->sockets, sk);
 
        pr_debug("Socket bound to SAP %d\n", llcp_sock->ssap);
 
@@ -304,11 +340,24 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock,
                mask |= POLLERR;
 
        if (!skb_queue_empty(&sk->sk_receive_queue))
-               mask |= POLLIN;
+               mask |= POLLIN | POLLRDNORM;
 
        if (sk->sk_state == LLCP_CLOSED)
                mask |= POLLHUP;
 
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP | POLLIN | POLLRDNORM;
+
+       if (sk->sk_shutdown == SHUTDOWN_MASK)
+               mask |= POLLHUP;
+
+       if (sock_writeable(sk))
+               mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+       else
+               set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+
+       pr_debug("mask 0x%x\n", mask);
+
        return mask;
 }
 
@@ -330,15 +379,6 @@ static int llcp_sock_release(struct socket *sock)
                goto out;
        }
 
-       mutex_lock(&local->socket_lock);
-
-       if (llcp_sock == local->sockets[llcp_sock->ssap])
-               local->sockets[llcp_sock->ssap] = NULL;
-       else
-               list_del_init(&llcp_sock->list);
-
-       mutex_unlock(&local->socket_lock);
-
        lock_sock(sk);
 
        /* Send a DISC */
@@ -363,14 +403,12 @@ static int llcp_sock_release(struct socket *sock)
                }
        }
 
-       /* Freeing the SAP */
-       if ((sk->sk_state == LLCP_CONNECTED
-            && llcp_sock->ssap > LLCP_LOCAL_SAP_OFFSET) ||
-           sk->sk_state == LLCP_BOUND || sk->sk_state == LLCP_LISTEN)
-               nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
+       nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
 
        release_sock(sk);
 
+       nfc_llcp_sock_unlink(&local->sockets, sk);
+
 out:
        sock_orphan(sk);
        sock_put(sk);
@@ -438,7 +476,8 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
        }
 
        llcp_sock->dev = dev;
-       llcp_sock->local = local;
+       llcp_sock->local = nfc_llcp_local_get(local);
+       llcp_sock->miu = llcp_sock->local->remote_miu;
        llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
        if (llcp_sock->ssap == LLCP_SAP_MAX) {
                ret = -ENOMEM;
@@ -456,17 +495,26 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
                                          llcp_sock->service_name_len,
                                          GFP_KERNEL);
 
-       local->sockets[llcp_sock->ssap] = llcp_sock;
+       nfc_llcp_sock_link(&local->connecting_sockets, sk);
 
        ret = nfc_llcp_send_connect(llcp_sock);
        if (ret)
-               goto put_dev;
+               goto sock_unlink;
 
-       sk->sk_state = LLCP_CONNECTED;
+       ret = sock_wait_state(sk, LLCP_CONNECTED,
+                             sock_sndtimeo(sk, flags & O_NONBLOCK));
+       if (ret)
+               goto sock_unlink;
 
        release_sock(sk);
+
        return 0;
 
+sock_unlink:
+       nfc_llcp_put_ssap(local, llcp_sock->ssap);
+
+       nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
+
 put_dev:
        nfc_put_device(dev);
 
@@ -631,13 +679,14 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
 
        llcp_sock->ssap = 0;
        llcp_sock->dsap = LLCP_SAP_SDP;
+       llcp_sock->rw = LLCP_DEFAULT_RW;
+       llcp_sock->miu = LLCP_DEFAULT_MIU;
        llcp_sock->send_n = llcp_sock->send_ack_n = 0;
        llcp_sock->recv_n = llcp_sock->recv_ack_n = 0;
        llcp_sock->remote_ready = 1;
        skb_queue_head_init(&llcp_sock->tx_queue);
        skb_queue_head_init(&llcp_sock->tx_pending_queue);
        skb_queue_head_init(&llcp_sock->tx_backlog_queue);
-       INIT_LIST_HEAD(&llcp_sock->list);
        INIT_LIST_HEAD(&llcp_sock->accept_queue);
 
        if (sock != NULL)
@@ -648,8 +697,6 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
 
 void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
 {
-       struct nfc_llcp_local *local = sock->local;
-
        kfree(sock->service_name);
 
        skb_queue_purge(&sock->tx_queue);
@@ -658,12 +705,9 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
 
        list_del_init(&sock->accept_queue);
 
-       if (local != NULL && sock == local->sockets[sock->ssap])
-               local->sockets[sock->ssap] = NULL;
-       else
-               list_del_init(&sock->list);
-
        sock->parent = NULL;
+
+       nfc_llcp_local_put(sock->local);
 }
 
 static int llcp_sock_create(struct net *net, struct socket *sock,
This page took 0.046403 seconds and 5 git commands to generate.