Merge remote-tracking branch 'aosp/android-3.0' into develop-3.0-jb
[firefly-linux-kernel-4.4.55.git] / net / sctp / socket.c
index fbb70770ad05d05807d25b5527e5616a621f58e8..b70a3ee6016c20bc26a46f202a4b84e8909bc765 100644 (file)
@@ -57,6 +57,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/wait.h>
@@ -109,12 +111,12 @@ static void sctp_sock_migrate(struct sock *, struct sock *,
 static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;
 
 extern struct kmem_cache *sctp_bucket_cachep;
-extern int sysctl_sctp_mem[3];
+extern long sysctl_sctp_mem[3];
 extern int sysctl_sctp_rmem[3];
 extern int sysctl_sctp_wmem[3];
 
 static int sctp_memory_pressure;
-static atomic_t sctp_memory_allocated;
+static atomic_long_t sctp_memory_allocated;
 struct percpu_counter sctp_sockets_allocated;
 
 static void sctp_enter_memory_pressure(struct sock *sk)
@@ -656,11 +658,15 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
                        goto err_bindx_rem;
                }
 
-               if (sa_addr->v4.sin_port != htons(bp->port)) {
+               if (sa_addr->v4.sin_port &&
+                   sa_addr->v4.sin_port != htons(bp->port)) {
                        retval = -EINVAL;
                        goto err_bindx_rem;
                }
 
+               if (!sa_addr->v4.sin_port)
+                       sa_addr->v4.sin_port = htons(bp->port);
+
                /* FIXME - There is probably a need to check if sk->sk_saddr and
                 * sk->sk_rcv_addr are currently set to one of the addresses to
                 * be removed. This is something which needs to be looked into
@@ -1154,8 +1160,14 @@ out_free:
        SCTP_DEBUG_PRINTK("About to exit __sctp_connect() free asoc: %p"
                          " kaddrs: %p err: %d\n",
                          asoc, kaddrs, err);
-       if (asoc)
+       if (asoc) {
+               /* sctp_primitive_ASSOCIATE may have added this association
+                * To the hash table, try to unhash it, just in case, its a noop
+                * if it wasn't hashed so we're safe
+                */
+               sctp_unhash_established(asoc);
                sctp_association_free(asoc);
+       }
        return err;
 }
 
@@ -1191,7 +1203,7 @@ out_free:
  * an endpoint that is multi-homed.  Much like sctp_bindx() this call
  * allows a caller to specify multiple addresses at which a peer can be
  * reached.  The way the SCTP stack uses the list of addresses to set up
- * the association is implementation dependant.  This function only
+ * the association is implementation dependent.  This function only
  * specifies that the stack will try to make use of all the addresses in
  * the list when needed.
  *
@@ -1378,6 +1390,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
        struct sctp_endpoint *ep;
        struct sctp_association *asoc;
        struct list_head *pos, *temp;
+       unsigned int data_was_unread;
 
        SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout);
 
@@ -1387,6 +1400,10 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
 
        ep = sctp_sk(sk)->ep;
 
+       /* Clean up any skbs sitting on the receive queue.  */
+       data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue);
+       data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby);
+
        /* Walk all associations on an endpoint.  */
        list_for_each_safe(pos, temp, &ep->asocs) {
                asoc = list_entry(pos, struct sctp_association, asocs);
@@ -1404,7 +1421,9 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
                        }
                }
 
-               if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
+               if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) ||
+                   !skb_queue_empty(&asoc->ulpq.reasm) ||
+                   (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) {
                        struct sctp_chunk *chunk;
 
                        chunk = sctp_make_abort_user(asoc, NULL, 0);
@@ -1414,10 +1433,6 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
                        sctp_primitive_SHUTDOWN(asoc, NULL);
        }
 
-       /* Clean up any skbs sitting on the receive queue.  */
-       sctp_queue_purge_ulpevents(&sk->sk_receive_queue);
-       sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby);
-
        /* On a TCP-style socket, block for at most linger_time if set. */
        if (sctp_style(sk, TCP) && timeout)
                sctp_wait_for_close(sk, timeout);
@@ -1490,7 +1505,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        struct sctp_chunk *chunk;
        union sctp_addr to;
        struct sockaddr *msg_name = NULL;
-       struct sctp_sndrcvinfo default_sinfo = { 0 };
+       struct sctp_sndrcvinfo default_sinfo;
        struct sctp_sndrcvinfo *sinfo;
        struct sctp_initmsg *sinit;
        sctp_assoc_t associd = 0;
@@ -1754,6 +1769,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                /* If the user didn't specify SNDRCVINFO, make up one with
                 * some defaults.
                 */
+               memset(&default_sinfo, 0, sizeof(default_sinfo));
                default_sinfo.sinfo_stream = asoc->default_stream;
                default_sinfo.sinfo_flags = asoc->default_flags;
                default_sinfo.sinfo_ppid = asoc->default_ppid;
@@ -1784,12 +1800,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                goto out_free;
        }
 
-       if (sinfo) {
-               /* Check for invalid stream. */
-               if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) {
-                       err = -EINVAL;
-                       goto out_free;
-               }
+       /* Check for invalid stream. */
+       if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) {
+               err = -EINVAL;
+               goto out_free;
        }
 
        timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
@@ -1863,8 +1877,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        goto out_unlock;
 
 out_free:
-       if (new_asoc)
+       if (new_asoc) {
+               sctp_unhash_established(asoc);
                sctp_association_free(asoc);
+       }
 out_unlock:
        sctp_release_sock(sk);
 
@@ -2068,10 +2084,33 @@ static int sctp_setsockopt_disable_fragments(struct sock *sk,
 static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
                                  unsigned int optlen)
 {
+       struct sctp_association *asoc;
+       struct sctp_ulpevent *event;
+
        if (optlen > sizeof(struct sctp_event_subscribe))
                return -EINVAL;
        if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen))
                return -EFAULT;
+
+       /*
+        * At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT,
+        * if there is no data to be sent or retransmit, the stack will
+        * immediately send up this notification.
+        */
+       if (sctp_ulpevent_type_enabled(SCTP_SENDER_DRY_EVENT,
+                                      &sctp_sk(sk)->subscribe)) {
+               asoc = sctp_id2assoc(sk, 0);
+
+               if (asoc && sctp_outq_is_empty(&asoc->outqueue)) {
+                       event = sctp_ulpevent_make_sender_dry_event(asoc,
+                                       GFP_ATOMIC);
+                       if (!event)
+                               return -ENOMEM;
+
+                       sctp_ulpq_tail_event(&asoc->ulpq, event);
+               }
+       }
+
        return 0;
 }
 
@@ -2098,8 +2137,6 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
                return -EINVAL;
        if (copy_from_user(&sp->autoclose, optval, optlen))
                return -EFAULT;
-       /* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */
-       sp->autoclose = min_t(long, sp->autoclose, MAX_SCHEDULE_TIMEOUT / HZ);
 
        return 0;
 }
@@ -2281,7 +2318,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
                        trans->param_flags =
                                (trans->param_flags & ~SPP_PMTUD) | pmtud_change;
                        if (update) {
-                               sctp_transport_pmtu(trans);
+                               sctp_transport_pmtu(trans, sctp_opt2sk(sp));
                                sctp_assoc_sync_pmtu(asoc);
                        }
                } else if (asoc) {
@@ -2469,9 +2506,8 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,
                if (params.sack_delay == 0 && params.sack_freq == 0)
                        return 0;
        } else if (optlen == sizeof(struct sctp_assoc_value)) {
-               printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
-                      "in delayed_ack socket option deprecated\n");
-               printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
+               pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n");
+               pr_warn("Use struct sctp_sack_info instead\n");
                if (copy_from_user(&params, optval, optlen))
                        return -EFAULT;
 
@@ -2879,10 +2915,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
        int val;
 
        if (optlen == sizeof(int)) {
-               printk(KERN_WARNING
-                  "SCTP: Use of int in maxseg socket option deprecated\n");
-               printk(KERN_WARNING
-                  "SCTP: Use struct sctp_assoc_value instead\n");
+               pr_warn("Use of int in maxseg socket option deprecated\n");
+               pr_warn("Use struct sctp_assoc_value instead\n");
                if (copy_from_user(&val, optval, optlen))
                        return -EFAULT;
                params.assoc_id = 0;
@@ -2929,14 +2963,13 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
                                             unsigned int optlen)
 {
        struct sctp_sock        *sp;
-       struct sctp_endpoint    *ep;
        struct sctp_association *asoc = NULL;
        struct sctp_setpeerprim prim;
        struct sctp_chunk       *chunk;
+       struct sctp_af          *af;
        int                     err;
 
        sp = sctp_sk(sk);
-       ep = sp->ep;
 
        if (!sctp_addip_enable)
                return -EPERM;
@@ -2960,6 +2993,13 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
        if (!sctp_state(asoc, ESTABLISHED))
                return -ENOTCONN;
 
+       af = sctp_get_af_specific(prim.sspp_addr.ss_family);
+       if (!af)
+               return -EINVAL;
+
+       if (!af->addr_valid((union sctp_addr *)&prim.sspp_addr, sp, NULL))
+               return -EADDRNOTAVAIL;
+
        if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr))
                return -EADDRNOTAVAIL;
 
@@ -3132,10 +3172,8 @@ static int sctp_setsockopt_maxburst(struct sock *sk,
        int assoc_id = 0;
 
        if (optlen == sizeof(int)) {
-               printk(KERN_WARNING
-                  "SCTP: Use of int in max_burst socket option deprecated\n");
-               printk(KERN_WARNING
-                  "SCTP: Use struct sctp_assoc_value instead\n");
+               pr_warn("Use of int in max_burst socket option deprecated\n");
+               pr_warn("Use struct sctp_assoc_value instead\n");
                if (copy_from_user(&val, optval, optlen))
                        return -EFAULT;
        } else if (optlen == sizeof(struct sctp_assoc_value)) {
@@ -3212,14 +3250,9 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,
        if (optlen < sizeof(struct sctp_hmacalgo))
                return -EINVAL;
 
-       hmacs = kmalloc(optlen, GFP_KERNEL);
-       if (!hmacs)
-               return -ENOMEM;
-
-       if (copy_from_user(hmacs, optval, optlen)) {
-               err = -EFAULT;
-               goto out;
-       }
+       hmacs= memdup_user(optval, optlen);
+       if (IS_ERR(hmacs))
+               return PTR_ERR(hmacs);
 
        idents = hmacs->shmac_num_idents;
        if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS ||
@@ -3254,14 +3287,9 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
        if (optlen <= sizeof(struct sctp_authkey))
                return -EINVAL;
 
-       authkey = kmalloc(optlen, GFP_KERNEL);
-       if (!authkey)
-               return -ENOMEM;
-
-       if (copy_from_user(authkey, optval, optlen)) {
-               ret = -EFAULT;
-               goto out;
-       }
+       authkey= memdup_user(optval, optlen);
+       if (IS_ERR(authkey))
+               return PTR_ERR(authkey);
 
        if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) {
                ret = -EINVAL;
@@ -3423,7 +3451,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
                retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen);
                break;
 
-       case SCTP_DELAYED_ACK:
+       case SCTP_DELAYED_SACK:
                retval = sctp_setsockopt_delayed_ack(sk, optval, optlen);
                break;
        case SCTP_PARTIAL_DELIVERY_POINT:
@@ -3606,7 +3634,40 @@ out:
 /* The SCTP ioctl handler. */
 SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
-       return -ENOIOCTLCMD;
+       int rc = -ENOTCONN;
+
+       sctp_lock_sock(sk);
+
+       /*
+        * SEQPACKET-style sockets in LISTENING state are valid, for
+        * SCTP, so only discard TCP-style sockets in LISTENING state.
+        */
+       if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
+               goto out;
+
+       switch (cmd) {
+       case SIOCINQ: {
+               struct sk_buff *skb;
+               unsigned int amount = 0;
+
+               skb = skb_peek(&sk->sk_receive_queue);
+               if (skb != NULL) {
+                       /*
+                        * We will only return the amount of this packet since
+                        * that is all that will be read.
+                        */
+                       amount = skb->len;
+               }
+               rc = put_user(amount, (int __user *)arg);
+               break;
+       }
+       default:
+               rc = -ENOIOCTLCMD;
+               break;
+       }
+out:
+       sctp_release_sock(sk);
+       return rc;
 }
 
 /* This is the function which gets called during socket creation to
@@ -3865,7 +3926,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
        }
 
 out:
-       return (retval);
+       return retval;
 }
 
 
@@ -3921,7 +3982,7 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,
        }
 
 out:
-       return (retval);
+       return retval;
 }
 
 /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS)
@@ -3956,9 +4017,10 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
 static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval,
                                  int __user *optlen)
 {
-       if (len < sizeof(struct sctp_event_subscribe))
+       if (len <= 0)
                return -EINVAL;
-       len = sizeof(struct sctp_event_subscribe);
+       if (len > sizeof(struct sctp_event_subscribe))
+               len = sizeof(struct sctp_event_subscribe);
        if (put_user(len, optlen))
                return -EFAULT;
        if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len))
@@ -4292,9 +4354,8 @@ static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,
                if (copy_from_user(&params, optval, len))
                        return -EFAULT;
        } else if (len == sizeof(struct sctp_assoc_value)) {
-               printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
-                      "in delayed_ack socket option deprecated\n");
-               printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
+               pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n");
+               pr_warn("Use struct sctp_sack_info instead\n");
                if (copy_from_user(&params, optval, len))
                        return -EFAULT;
        } else
@@ -4940,10 +5001,8 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len,
        struct sctp_association *asoc;
 
        if (len == sizeof(int)) {
-               printk(KERN_WARNING
-                  "SCTP: Use of int in maxseg socket option deprecated\n");
-               printk(KERN_WARNING
-                  "SCTP: Use struct sctp_assoc_value instead\n");
+               pr_warn("Use of int in maxseg socket option deprecated\n");
+               pr_warn("Use struct sctp_assoc_value instead\n");
                params.assoc_id = 0;
        } else if (len >= sizeof(struct sctp_assoc_value)) {
                len = sizeof(struct sctp_assoc_value);
@@ -5018,7 +5077,7 @@ static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len,
        if (copy_to_user(optval, &val, len))
                return -EFAULT;
 
-       return -ENOTSUPP;
+       return 0;
 }
 
 /*
@@ -5034,10 +5093,8 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
        struct sctp_association *asoc;
 
        if (len == sizeof(int)) {
-               printk(KERN_WARNING
-                  "SCTP: Use of int in max_burst socket option deprecated\n");
-               printk(KERN_WARNING
-                  "SCTP: Use struct sctp_assoc_value instead\n");
+               pr_warn("Use of int in max_burst socket option deprecated\n");
+               pr_warn("Use struct sctp_assoc_value instead\n");
                params.assoc_id = 0;
        } else if (len >= sizeof(struct sctp_assoc_value)) {
                len = sizeof(struct sctp_assoc_value);
@@ -5252,6 +5309,55 @@ static int sctp_getsockopt_assoc_number(struct sock *sk, int len,
        return 0;
 }
 
+/*
+ * 8.2.6. Get the Current Identifiers of Associations
+ *        (SCTP_GET_ASSOC_ID_LIST)
+ *
+ * This option gets the current list of SCTP association identifiers of
+ * the SCTP associations handled by a one-to-many style socket.
+ */
+static int sctp_getsockopt_assoc_ids(struct sock *sk, int len,
+                                   char __user *optval, int __user *optlen)
+{
+       struct sctp_sock *sp = sctp_sk(sk);
+       struct sctp_association *asoc;
+       struct sctp_assoc_ids *ids;
+       u32 num = 0;
+
+       if (sctp_style(sk, TCP))
+               return -EOPNOTSUPP;
+
+       if (len < sizeof(struct sctp_assoc_ids))
+               return -EINVAL;
+
+       list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
+               num++;
+       }
+
+       if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num)
+               return -EINVAL;
+
+       len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num;
+
+       ids = kmalloc(len, GFP_KERNEL);
+       if (unlikely(!ids))
+               return -ENOMEM;
+
+       ids->gaids_number_of_ids = num;
+       num = 0;
+       list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
+               ids->gaids_assoc_id[num++] = asoc->assoc_id;
+       }
+
+       if (put_user(len, optlen) || copy_to_user(optval, ids, len)) {
+               kfree(ids);
+               return -EFAULT;
+       }
+
+       kfree(ids);
+       return 0;
+}
+
 SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                                char __user *optval, int __user *optlen)
 {
@@ -5300,7 +5406,7 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
                                                          optlen);
                break;
-       case SCTP_DELAYED_ACK:
+       case SCTP_DELAYED_SACK:
                retval = sctp_getsockopt_delayed_ack(sk, len, optval,
                                                          optlen);
                break;
@@ -5384,6 +5490,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
        case SCTP_GET_ASSOC_NUMBER:
                retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen);
                break;
+       case SCTP_GET_ASSOC_ID_LIST:
+               retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -5580,7 +5689,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
        /* Note: sk->sk_num gets filled in if ephemeral port request. */
        ret = sctp_get_port_local(sk, &addr);
 
-       return (ret ? 1 : 0);
+       return ret ? 1 : 0;
 }
 
 /*
@@ -5597,8 +5706,7 @@ SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog)
                tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
                if (IS_ERR(tfm)) {
                        if (net_ratelimit()) {
-                               printk(KERN_INFO
-                                      "SCTP: failed to load transform for %s: %ld\n",
+                               pr_info("failed to load transform for %s: %ld\n",
                                        sctp_hmac_alg, PTR_ERR(tfm));
                        }
                        return -ENOSYS;
@@ -5727,13 +5835,12 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
        if (sk->sk_shutdown & RCV_SHUTDOWN)
-               mask |= POLLRDHUP;
+               mask |= POLLRDHUP | POLLIN | POLLRDNORM;
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
        /* Is it readable?  Reconsider this code with TCP-style support.  */
-       if (!skb_queue_empty(&sk->sk_receive_queue) ||
-           (sk->sk_shutdown & RCV_SHUTDOWN))
+       if (!skb_queue_empty(&sk->sk_receive_queue))
                mask |= POLLIN | POLLRDNORM;
 
        /* The association is either gone or not ready.  */
@@ -6024,7 +6131,7 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
                 * will suddenly eat the receive_queue.
                 *
                 *  Look at current nfs client by the way...
-                *  However, this function was corrent in any case. 8)
+                *  However, this function was correct in any case. 8)
                 */
                if (flags & MSG_PEEK) {
                        spin_lock_bh(&sk->sk_receive_queue.lock);
@@ -6071,15 +6178,16 @@ static void __sctp_write_space(struct sctp_association *asoc)
                        wake_up_interruptible(&asoc->wait);
 
                if (sctp_writeable(sk)) {
-                       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
-                               wake_up_interruptible(sk_sleep(sk));
+                       wait_queue_head_t *wq = sk_sleep(sk);
+
+                       if (wq && waitqueue_active(wq))
+                               wake_up_interruptible(wq);
 
                        /* Note that we try to include the Async I/O support
                         * here by modeling from the current TCP/UDP code.
                         * We have not tested with it yet.
                         */
-                       if (sock->wq->fasync_list &&
-                           !(sk->sk_shutdown & SEND_SHUTDOWN))
+                       if (!(sk->sk_shutdown & SEND_SHUTDOWN))
                                sock_wake_async(sock,
                                                SOCK_WAKE_SPACE, POLL_OUT);
                }