]> git.karo-electronics.de Git - linux-beck.git/blobdiff - net/sctp/socket.c
Merge remote-tracking branch 'regulator/fix/of' into tmp
[linux-beck.git] / net / sctp / socket.c
index 406d957d08fbcb7d9cb532a8143d363c277c3ec8..9e65758cb03814f9372eafbf86c4821af124be00 100644 (file)
@@ -110,7 +110,6 @@ static int sctp_do_bind(struct sock *, union sctp_addr *, int);
 static int sctp_autobind(struct sock *sk);
 static void sctp_sock_migrate(struct sock *, struct sock *,
                              struct sctp_association *, sctp_socket_type_t);
-static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;
 
 extern struct kmem_cache *sctp_bucket_cachep;
 extern long sysctl_sctp_mem[3];
@@ -336,6 +335,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
 /* Bind a local address either to an endpoint or to an association.  */
 SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
 {
+       struct net *net = sock_net(sk);
        struct sctp_sock *sp = sctp_sk(sk);
        struct sctp_endpoint *ep = sp->ep;
        struct sctp_bind_addr *bp = &ep->base.bind_addr;
@@ -379,7 +379,8 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
                }
        }
 
-       if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+       if (snum && snum < PROT_SOCK &&
+           !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
                return -EACCES;
 
        /* See if the address matches any of the addresses we may have
@@ -610,6 +611,7 @@ static int sctp_send_asconf_add_ip(struct sock              *sk,
                                    2*asoc->pathmtu, 4380));
                                trans->ssthresh = asoc->peer.i.a_rwnd;
                                trans->rto = asoc->rto_initial;
+                               sctp_max_rto(asoc, trans);
                                trans->rtt = trans->srtt = trans->rttvar = 0;
                                sctp_transport_route(trans, NULL,
                                    sctp_sk(asoc->base.sk));
@@ -1162,7 +1164,7 @@ static int __sctp_connect(struct sock* sk,
                                 * be permitted to open new associations.
                                 */
                                if (ep->base.bind_addr.port < PROT_SOCK &&
-                                   !capable(CAP_NET_BIND_SERVICE)) {
+                                   !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) {
                                        err = -EACCES;
                                        goto out_free;
                                }
@@ -1791,7 +1793,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                         * associations.
                         */
                        if (ep->base.bind_addr.port < PROT_SOCK &&
-                           !capable(CAP_NET_BIND_SERVICE)) {
+                           !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) {
                                err = -EACCES;
                                goto out_unlock;
                        }
@@ -3890,6 +3892,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        sp->default_rcv_context = 0;
        sp->max_burst = net->sctp.max_burst;
 
+       sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg;
+
        /* Initialize default setup parameters. These parameters
         * can be modified with the SCTP_INITMSG socket option or
         * overridden by the SCTP_INIT CMSG.
@@ -5632,6 +5636,71 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
        return 0;
 }
 
+/*
+ * SCTP_GET_ASSOC_STATS
+ *
+ * This option retrieves local per endpoint statistics. It is modeled
+ * after OpenSolaris' implementation
+ */
+static int sctp_getsockopt_assoc_stats(struct sock *sk, int len,
+                                      char __user *optval,
+                                      int __user *optlen)
+{
+       struct sctp_assoc_stats sas;
+       struct sctp_association *asoc = NULL;
+
+       /* User must provide at least the assoc id */
+       if (len < sizeof(sctp_assoc_t))
+               return -EINVAL;
+
+       if (copy_from_user(&sas, optval, len))
+               return -EFAULT;
+
+       asoc = sctp_id2assoc(sk, sas.sas_assoc_id);
+       if (!asoc)
+               return -EINVAL;
+
+       sas.sas_rtxchunks = asoc->stats.rtxchunks;
+       sas.sas_gapcnt = asoc->stats.gapcnt;
+       sas.sas_outofseqtsns = asoc->stats.outofseqtsns;
+       sas.sas_osacks = asoc->stats.osacks;
+       sas.sas_isacks = asoc->stats.isacks;
+       sas.sas_octrlchunks = asoc->stats.octrlchunks;
+       sas.sas_ictrlchunks = asoc->stats.ictrlchunks;
+       sas.sas_oodchunks = asoc->stats.oodchunks;
+       sas.sas_iodchunks = asoc->stats.iodchunks;
+       sas.sas_ouodchunks = asoc->stats.ouodchunks;
+       sas.sas_iuodchunks = asoc->stats.iuodchunks;
+       sas.sas_idupchunks = asoc->stats.idupchunks;
+       sas.sas_opackets = asoc->stats.opackets;
+       sas.sas_ipackets = asoc->stats.ipackets;
+
+       /* New high max rto observed, will return 0 if not a single
+        * RTO update took place. obs_rto_ipaddr will be bogus
+        * in such a case
+        */
+       sas.sas_maxrto = asoc->stats.max_obs_rto;
+       memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr,
+               sizeof(struct sockaddr_storage));
+
+       /* Mark beginning of a new observation period */
+       asoc->stats.max_obs_rto = asoc->rto_min;
+
+       /* Allow the struct to grow and fill in as much as possible */
+       len = min_t(size_t, len, sizeof(sas));
+
+       if (put_user(len, optlen))
+               return -EFAULT;
+
+       SCTP_DEBUG_PRINTK("sctp_getsockopt_assoc_stat(%d): %d\n",
+                         len, sas.sas_assoc_id);
+
+       if (copy_to_user(optval, &sas, len))
+               return -EFAULT;
+
+       return 0;
+}
+
 SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                                char __user *optval, int __user *optlen)
 {
@@ -5773,6 +5842,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
        case SCTP_PEER_ADDR_THLDS:
                retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen);
                break;
+       case SCTP_GET_ASSOC_STATS:
+               retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -5981,13 +6053,15 @@ SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog)
        struct sctp_sock *sp = sctp_sk(sk);
        struct sctp_endpoint *ep = sp->ep;
        struct crypto_hash *tfm = NULL;
+       char alg[32];
 
        /* Allocate HMAC for generating cookie. */
-       if (!sctp_sk(sk)->hmac && sctp_hmac_alg) {
-               tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
+       if (!sp->hmac && sp->sctp_hmac_alg) {
+               sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg);
+               tfm = crypto_alloc_hash(alg, 0, CRYPTO_ALG_ASYNC);
                if (IS_ERR(tfm)) {
                        net_info_ratelimited("failed to load transform for %s: %ld\n",
-                                            sctp_hmac_alg, PTR_ERR(tfm));
+                                            sp->sctp_hmac_alg, PTR_ERR(tfm));
                        return -ENOSYS;
                }
                sctp_sk(sk)->hmac = tfm;