diff options
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 88 |
1 files changed, 81 insertions, 7 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 406d957d08fb..9e65758cb038 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -110,7 +110,6 @@ static int sctp_do_bind(struct sock *, union sctp_addr *, int); | |||
110 | static int sctp_autobind(struct sock *sk); | 110 | static int sctp_autobind(struct sock *sk); |
111 | static void sctp_sock_migrate(struct sock *, struct sock *, | 111 | static void sctp_sock_migrate(struct sock *, struct sock *, |
112 | struct sctp_association *, sctp_socket_type_t); | 112 | struct sctp_association *, sctp_socket_type_t); |
113 | static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; | ||
114 | 113 | ||
115 | extern struct kmem_cache *sctp_bucket_cachep; | 114 | extern struct kmem_cache *sctp_bucket_cachep; |
116 | extern long sysctl_sctp_mem[3]; | 115 | extern long sysctl_sctp_mem[3]; |
@@ -336,6 +335,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, | |||
336 | /* Bind a local address either to an endpoint or to an association. */ | 335 | /* Bind a local address either to an endpoint or to an association. */ |
337 | SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) | 336 | SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) |
338 | { | 337 | { |
338 | struct net *net = sock_net(sk); | ||
339 | struct sctp_sock *sp = sctp_sk(sk); | 339 | struct sctp_sock *sp = sctp_sk(sk); |
340 | struct sctp_endpoint *ep = sp->ep; | 340 | struct sctp_endpoint *ep = sp->ep; |
341 | struct sctp_bind_addr *bp = &ep->base.bind_addr; | 341 | 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) | |||
379 | } | 379 | } |
380 | } | 380 | } |
381 | 381 | ||
382 | if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) | 382 | if (snum && snum < PROT_SOCK && |
383 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) | ||
383 | return -EACCES; | 384 | return -EACCES; |
384 | 385 | ||
385 | /* See if the address matches any of the addresses we may have | 386 | /* 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, | |||
610 | 2*asoc->pathmtu, 4380)); | 611 | 2*asoc->pathmtu, 4380)); |
611 | trans->ssthresh = asoc->peer.i.a_rwnd; | 612 | trans->ssthresh = asoc->peer.i.a_rwnd; |
612 | trans->rto = asoc->rto_initial; | 613 | trans->rto = asoc->rto_initial; |
614 | sctp_max_rto(asoc, trans); | ||
613 | trans->rtt = trans->srtt = trans->rttvar = 0; | 615 | trans->rtt = trans->srtt = trans->rttvar = 0; |
614 | sctp_transport_route(trans, NULL, | 616 | sctp_transport_route(trans, NULL, |
615 | sctp_sk(asoc->base.sk)); | 617 | sctp_sk(asoc->base.sk)); |
@@ -1162,7 +1164,7 @@ static int __sctp_connect(struct sock* sk, | |||
1162 | * be permitted to open new associations. | 1164 | * be permitted to open new associations. |
1163 | */ | 1165 | */ |
1164 | if (ep->base.bind_addr.port < PROT_SOCK && | 1166 | if (ep->base.bind_addr.port < PROT_SOCK && |
1165 | !capable(CAP_NET_BIND_SERVICE)) { | 1167 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { |
1166 | err = -EACCES; | 1168 | err = -EACCES; |
1167 | goto out_free; | 1169 | goto out_free; |
1168 | } | 1170 | } |
@@ -1791,7 +1793,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1791 | * associations. | 1793 | * associations. |
1792 | */ | 1794 | */ |
1793 | if (ep->base.bind_addr.port < PROT_SOCK && | 1795 | if (ep->base.bind_addr.port < PROT_SOCK && |
1794 | !capable(CAP_NET_BIND_SERVICE)) { | 1796 | !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) { |
1795 | err = -EACCES; | 1797 | err = -EACCES; |
1796 | goto out_unlock; | 1798 | goto out_unlock; |
1797 | } | 1799 | } |
@@ -3890,6 +3892,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3890 | sp->default_rcv_context = 0; | 3892 | sp->default_rcv_context = 0; |
3891 | sp->max_burst = net->sctp.max_burst; | 3893 | sp->max_burst = net->sctp.max_burst; |
3892 | 3894 | ||
3895 | sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg; | ||
3896 | |||
3893 | /* Initialize default setup parameters. These parameters | 3897 | /* Initialize default setup parameters. These parameters |
3894 | * can be modified with the SCTP_INITMSG socket option or | 3898 | * can be modified with the SCTP_INITMSG socket option or |
3895 | * overridden by the SCTP_INIT CMSG. | 3899 | * overridden by the SCTP_INIT CMSG. |
@@ -5632,6 +5636,71 @@ static int sctp_getsockopt_paddr_thresholds(struct sock *sk, | |||
5632 | return 0; | 5636 | return 0; |
5633 | } | 5637 | } |
5634 | 5638 | ||
5639 | /* | ||
5640 | * SCTP_GET_ASSOC_STATS | ||
5641 | * | ||
5642 | * This option retrieves local per endpoint statistics. It is modeled | ||
5643 | * after OpenSolaris' implementation | ||
5644 | */ | ||
5645 | static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, | ||
5646 | char __user *optval, | ||
5647 | int __user *optlen) | ||
5648 | { | ||
5649 | struct sctp_assoc_stats sas; | ||
5650 | struct sctp_association *asoc = NULL; | ||
5651 | |||
5652 | /* User must provide at least the assoc id */ | ||
5653 | if (len < sizeof(sctp_assoc_t)) | ||
5654 | return -EINVAL; | ||
5655 | |||
5656 | if (copy_from_user(&sas, optval, len)) | ||
5657 | return -EFAULT; | ||
5658 | |||
5659 | asoc = sctp_id2assoc(sk, sas.sas_assoc_id); | ||
5660 | if (!asoc) | ||
5661 | return -EINVAL; | ||
5662 | |||
5663 | sas.sas_rtxchunks = asoc->stats.rtxchunks; | ||
5664 | sas.sas_gapcnt = asoc->stats.gapcnt; | ||
5665 | sas.sas_outofseqtsns = asoc->stats.outofseqtsns; | ||
5666 | sas.sas_osacks = asoc->stats.osacks; | ||
5667 | sas.sas_isacks = asoc->stats.isacks; | ||
5668 | sas.sas_octrlchunks = asoc->stats.octrlchunks; | ||
5669 | sas.sas_ictrlchunks = asoc->stats.ictrlchunks; | ||
5670 | sas.sas_oodchunks = asoc->stats.oodchunks; | ||
5671 | sas.sas_iodchunks = asoc->stats.iodchunks; | ||
5672 | sas.sas_ouodchunks = asoc->stats.ouodchunks; | ||
5673 | sas.sas_iuodchunks = asoc->stats.iuodchunks; | ||
5674 | sas.sas_idupchunks = asoc->stats.idupchunks; | ||
5675 | sas.sas_opackets = asoc->stats.opackets; | ||
5676 | sas.sas_ipackets = asoc->stats.ipackets; | ||
5677 | |||
5678 | /* New high max rto observed, will return 0 if not a single | ||
5679 | * RTO update took place. obs_rto_ipaddr will be bogus | ||
5680 | * in such a case | ||
5681 | */ | ||
5682 | sas.sas_maxrto = asoc->stats.max_obs_rto; | ||
5683 | memcpy(&sas.sas_obs_rto_ipaddr, &asoc->stats.obs_rto_ipaddr, | ||
5684 | sizeof(struct sockaddr_storage)); | ||
5685 | |||
5686 | /* Mark beginning of a new observation period */ | ||
5687 | asoc->stats.max_obs_rto = asoc->rto_min; | ||
5688 | |||
5689 | /* Allow the struct to grow and fill in as much as possible */ | ||
5690 | len = min_t(size_t, len, sizeof(sas)); | ||
5691 | |||
5692 | if (put_user(len, optlen)) | ||
5693 | return -EFAULT; | ||
5694 | |||
5695 | SCTP_DEBUG_PRINTK("sctp_getsockopt_assoc_stat(%d): %d\n", | ||
5696 | len, sas.sas_assoc_id); | ||
5697 | |||
5698 | if (copy_to_user(optval, &sas, len)) | ||
5699 | return -EFAULT; | ||
5700 | |||
5701 | return 0; | ||
5702 | } | ||
5703 | |||
5635 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | 5704 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, |
5636 | char __user *optval, int __user *optlen) | 5705 | char __user *optval, int __user *optlen) |
5637 | { | 5706 | { |
@@ -5773,6 +5842,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
5773 | case SCTP_PEER_ADDR_THLDS: | 5842 | case SCTP_PEER_ADDR_THLDS: |
5774 | retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen); | 5843 | retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen); |
5775 | break; | 5844 | break; |
5845 | case SCTP_GET_ASSOC_STATS: | ||
5846 | retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); | ||
5847 | break; | ||
5776 | default: | 5848 | default: |
5777 | retval = -ENOPROTOOPT; | 5849 | retval = -ENOPROTOOPT; |
5778 | break; | 5850 | break; |
@@ -5981,13 +6053,15 @@ SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog) | |||
5981 | struct sctp_sock *sp = sctp_sk(sk); | 6053 | struct sctp_sock *sp = sctp_sk(sk); |
5982 | struct sctp_endpoint *ep = sp->ep; | 6054 | struct sctp_endpoint *ep = sp->ep; |
5983 | struct crypto_hash *tfm = NULL; | 6055 | struct crypto_hash *tfm = NULL; |
6056 | char alg[32]; | ||
5984 | 6057 | ||
5985 | /* Allocate HMAC for generating cookie. */ | 6058 | /* Allocate HMAC for generating cookie. */ |
5986 | if (!sctp_sk(sk)->hmac && sctp_hmac_alg) { | 6059 | if (!sp->hmac && sp->sctp_hmac_alg) { |
5987 | tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC); | 6060 | sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg); |
6061 | tfm = crypto_alloc_hash(alg, 0, CRYPTO_ALG_ASYNC); | ||
5988 | if (IS_ERR(tfm)) { | 6062 | if (IS_ERR(tfm)) { |
5989 | net_info_ratelimited("failed to load transform for %s: %ld\n", | 6063 | net_info_ratelimited("failed to load transform for %s: %ld\n", |
5990 | sctp_hmac_alg, PTR_ERR(tfm)); | 6064 | sp->sctp_hmac_alg, PTR_ERR(tfm)); |
5991 | return -ENOSYS; | 6065 | return -ENOSYS; |
5992 | } | 6066 | } |
5993 | sctp_sk(sk)->hmac = tfm; | 6067 | sctp_sk(sk)->hmac = tfm; |