]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/sctp/socket.c
tcp: add TCPMemoryPressuresChrono counter
[karo-tx-linux.git] / net / sctp / socket.c
index c1401f43d40fc5c5a85dbcbcba424ad2e649ab56..5f58dd03e3ace38b9c4babbe2d92f0a3f98a4b68 100644 (file)
@@ -103,7 +103,7 @@ static int sctp_autobind(struct sock *sk);
 static void sctp_sock_migrate(struct sock *, struct sock *,
                              struct sctp_association *, sctp_socket_type_t);
 
-static int sctp_memory_pressure;
+static unsigned long sctp_memory_pressure;
 static atomic_long_t sctp_memory_allocated;
 struct percpu_counter sctp_sockets_allocated;
 
@@ -1920,7 +1920,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
        }
 
        /* Check for invalid stream. */
-       if (sinfo->sinfo_stream >= asoc->stream->outcnt) {
+       if (sinfo->sinfo_stream >= asoc->stream.outcnt) {
                err = -EINVAL;
                goto out_free;
        }
@@ -3758,6 +3758,39 @@ out:
        return retval;
 }
 
+static int sctp_setsockopt_reconfig_supported(struct sock *sk,
+                                             char __user *optval,
+                                             unsigned int optlen)
+{
+       struct sctp_assoc_value params;
+       struct sctp_association *asoc;
+       int retval = -EINVAL;
+
+       if (optlen != sizeof(params))
+               goto out;
+
+       if (copy_from_user(&params, optval, optlen)) {
+               retval = -EFAULT;
+               goto out;
+       }
+
+       asoc = sctp_id2assoc(sk, params.assoc_id);
+       if (asoc) {
+               asoc->reconf_enable = !!params.assoc_value;
+       } else if (!params.assoc_id) {
+               struct sctp_sock *sp = sctp_sk(sk);
+
+               sp->ep->reconf_enable = !!params.assoc_value;
+       } else {
+               goto out;
+       }
+
+       retval = 0;
+
+out:
+       return retval;
+}
+
 static int sctp_setsockopt_enable_strreset(struct sock *sk,
                                           char __user *optval,
                                           unsigned int optlen)
@@ -4038,6 +4071,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
        case SCTP_DEFAULT_PRINFO:
                retval = sctp_setsockopt_default_prinfo(sk, optval, optlen);
                break;
+       case SCTP_RECONFIG_SUPPORTED:
+               retval = sctp_setsockopt_reconfig_supported(sk, optval, optlen);
+               break;
        case SCTP_ENABLE_STREAM_RESET:
                retval = sctp_setsockopt_enable_strreset(sk, optval, optlen);
                break;
@@ -4461,8 +4497,8 @@ int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
        info->sctpi_rwnd = asoc->a_rwnd;
        info->sctpi_unackdata = asoc->unack_data;
        info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
-       info->sctpi_instrms = asoc->stream->incnt;
-       info->sctpi_outstrms = asoc->stream->outcnt;
+       info->sctpi_instrms = asoc->stream.incnt;
+       info->sctpi_outstrms = asoc->stream.outcnt;
        list_for_each(pos, &asoc->base.inqueue.in_chunk_list)
                info->sctpi_inqueue++;
        list_for_each(pos, &asoc->outqueue.out_chunk_list)
@@ -4691,8 +4727,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
        status.sstat_unackdata = asoc->unack_data;
 
        status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
-       status.sstat_instrms = asoc->stream->incnt;
-       status.sstat_outstrms = asoc->stream->outcnt;
+       status.sstat_instrms = asoc->stream.incnt;
+       status.sstat_outstrms = asoc->stream.outcnt;
        status.sstat_fragmentation_point = asoc->frag_point;
        status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
        memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr,
@@ -6540,6 +6576,102 @@ out:
        return retval;
 }
 
+static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len,
+                                          char __user *optval,
+                                          int __user *optlen)
+{
+       struct sctp_stream_out *streamout;
+       struct sctp_association *asoc;
+       struct sctp_prstatus params;
+       int retval = -EINVAL;
+       int policy;
+
+       if (len < sizeof(params))
+               goto out;
+
+       len = sizeof(params);
+       if (copy_from_user(&params, optval, len)) {
+               retval = -EFAULT;
+               goto out;
+       }
+
+       policy = params.sprstat_policy;
+       if (policy & ~SCTP_PR_SCTP_MASK)
+               goto out;
+
+       asoc = sctp_id2assoc(sk, params.sprstat_assoc_id);
+       if (!asoc || params.sprstat_sid >= asoc->stream.outcnt)
+               goto out;
+
+       streamout = &asoc->stream.out[params.sprstat_sid];
+       if (policy == SCTP_PR_SCTP_NONE) {
+               params.sprstat_abandoned_unsent = 0;
+               params.sprstat_abandoned_sent = 0;
+               for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) {
+                       params.sprstat_abandoned_unsent +=
+                               streamout->abandoned_unsent[policy];
+                       params.sprstat_abandoned_sent +=
+                               streamout->abandoned_sent[policy];
+               }
+       } else {
+               params.sprstat_abandoned_unsent =
+                       streamout->abandoned_unsent[__SCTP_PR_INDEX(policy)];
+               params.sprstat_abandoned_sent =
+                       streamout->abandoned_sent[__SCTP_PR_INDEX(policy)];
+       }
+
+       if (put_user(len, optlen) || copy_to_user(optval, &params, len)) {
+               retval = -EFAULT;
+               goto out;
+       }
+
+       retval = 0;
+
+out:
+       return retval;
+}
+
+static int sctp_getsockopt_reconfig_supported(struct sock *sk, int len,
+                                             char __user *optval,
+                                             int __user *optlen)
+{
+       struct sctp_assoc_value params;
+       struct sctp_association *asoc;
+       int retval = -EFAULT;
+
+       if (len < sizeof(params)) {
+               retval = -EINVAL;
+               goto out;
+       }
+
+       len = sizeof(params);
+       if (copy_from_user(&params, optval, len))
+               goto out;
+
+       asoc = sctp_id2assoc(sk, params.assoc_id);
+       if (asoc) {
+               params.assoc_value = asoc->reconf_enable;
+       } else if (!params.assoc_id) {
+               struct sctp_sock *sp = sctp_sk(sk);
+
+               params.assoc_value = sp->ep->reconf_enable;
+       } else {
+               retval = -EINVAL;
+               goto out;
+       }
+
+       if (put_user(len, optlen))
+               goto out;
+
+       if (copy_to_user(optval, &params, len))
+               goto out;
+
+       retval = 0;
+
+out:
+       return retval;
+}
+
 static int sctp_getsockopt_enable_strreset(struct sock *sk, int len,
                                           char __user *optval,
                                           int __user *optlen)
@@ -6748,6 +6880,14 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_pr_assocstatus(sk, len, optval,
                                                        optlen);
                break;
+       case SCTP_PR_STREAM_STATUS:
+               retval = sctp_getsockopt_pr_streamstatus(sk, len, optval,
+                                                        optlen);
+               break;
+       case SCTP_RECONFIG_SUPPORTED:
+               retval = sctp_getsockopt_reconfig_supported(sk, len, optval,
+                                                           optlen);
+               break;
        case SCTP_ENABLE_STREAM_RESET:
                retval = sctp_getsockopt_enable_strreset(sk, len, optval,
                                                         optlen);
@@ -7034,6 +7174,9 @@ int sctp_inet_listen(struct socket *sock, int backlog)
        if (sock->state != SS_UNCONNECTED)
                goto out;
 
+       if (!sctp_sstate(sk, LISTENING) && !sctp_sstate(sk, CLOSED))
+               goto out;
+
        /* If backlog is zero, disable listening. */
        if (!backlog) {
                if (sctp_sstate(sk, CLOSED))
@@ -7437,9 +7580,12 @@ struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
                if (sk->sk_shutdown & RCV_SHUTDOWN)
                        break;
 
-               if (sk_can_busy_loop(sk) &&
-                   sk_busy_loop(sk, noblock))
-                       continue;
+               if (sk_can_busy_loop(sk)) {
+                       sk_busy_loop(sk, noblock);
+
+                       if (!skb_queue_empty(&sk->sk_receive_queue))
+                               continue;
+               }
 
                /* User doesn't want to wait.  */
                error = -EAGAIN;