NFC: LLCP connect must wait for a CC frame
authorSamuel Ortiz <sameo@linux.intel.com>
Mon, 7 May 2012 10:31:19 +0000 (12:31 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 15 May 2012 21:28:01 +0000 (17:28 -0400)
Blocking sockets should sleep on a CC (Connection Complete) reception
from the connect() call.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/nfc/llcp/llcp.c
net/nfc/llcp/sock.c

index 92988aa620dcb04d73ae45eb573249bddac0a6cf..42994fac26d6c697671075eb86ed8321bfc75711 100644 (file)
@@ -448,6 +448,8 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
 {
        struct nfc_llcp_sock *sock, *llcp_sock, *n;
 
+       pr_debug("ssap dsap %d %d\n", ssap, dsap);
+
        if (ssap == 0 && dsap == 0)
                return NULL;
 
@@ -783,6 +785,7 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
 static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
 {
        struct nfc_llcp_sock *llcp_sock;
+       struct sock *sk;
        u8 dsap, ssap;
 
        dsap = nfc_llcp_dsap(skb);
@@ -801,10 +804,14 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
        }
 
        llcp_sock->dsap = ssap;
+       sk = &llcp_sock->sk;
 
        nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
                           skb->len - LLCP_HEADER_SIZE);
 
+       sk->sk_state = LLCP_CONNECTED;
+       sk->sk_state_change(sk);
+
        nfc_llcp_sock_put(llcp_sock);
 }
 
index c13e02ebdef9b08e5c995f5cbb5a671db42d8e3c..99196d3b84ebb3bc115edc9603d2eac4094f7792 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,
@@ -462,9 +498,13 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
        if (ret)
                goto put_dev;
 
-       sk->sk_state = LLCP_CONNECTED;
+       ret = sock_wait_state(sk, LLCP_CONNECTED,
+                             sock_sndtimeo(sk, flags & O_NONBLOCK));
+       if (ret)
+               goto put_dev;
 
        release_sock(sk);
+
        return 0;
 
 put_dev: