From ff353d86a92ee709e18fa485423dbaa7a52af8f3 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 7 May 2012 12:31:19 +0200 Subject: NFC: LLCP connect must wait for a CC frame Blocking sockets should sleep on a CC (Connection Complete) reception from the connect() call. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/sock.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'net/nfc/llcp/sock.c') diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index c13e02ebdef9..99196d3b84eb 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -27,6 +27,42 @@ #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: -- cgit From 4260c13ba9102d466f017139de990dfffaf4d997 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 7 May 2012 12:31:20 +0200 Subject: NFC: Update the LLCP poll mask Fix the poll mask depending on the socket state. POLLOUT was missing for example. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/sock.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'net/nfc/llcp/sock.c') diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 99196d3b84eb..3f339b19d140 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -340,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; } -- cgit