]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/sctp/socket.c
unexport sock_map_fd(), switch to sock_alloc_file()
[mirror_ubuntu-bionic-kernel.git] / net / sctp / socket.c
index 31c7bfcd9b5872aa136e2b513123bb6d582bdff6..fb5931ca50d0fc4aad0ac49d60b7591d981ea30f 100644 (file)
@@ -70,6 +70,7 @@
 #include <linux/init.h>
 #include <linux/crypto.h>
 #include <linux/slab.h>
+#include <linux/file.h>
 
 #include <net/ip.h>
 #include <net/icmp.h>
@@ -1859,7 +1860,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        }
 
        if (asoc->pmtu_pending)
-               sctp_assoc_pending_pmtu(asoc);
+               sctp_assoc_pending_pmtu(sk, asoc);
 
        /* If fragmentation is disabled and the message length exceeds the
         * association fragmentation point, return EMSGSIZE.  The I-D
@@ -2373,7 +2374,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
        if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) {
                if (trans) {
                        trans->pathmtu = params->spp_pathmtu;
-                       sctp_assoc_sync_pmtu(asoc);
+                       sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc);
                } else if (asoc) {
                        asoc->pathmtu = params->spp_pathmtu;
                        sctp_frag_point(asoc, params->spp_pathmtu);
@@ -2390,7 +2391,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
                                (trans->param_flags & ~SPP_PMTUD) | pmtud_change;
                        if (update) {
                                sctp_transport_pmtu(trans, sctp_opt2sk(sp));
-                               sctp_assoc_sync_pmtu(asoc);
+                               sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc);
                        }
                } else if (asoc) {
                        asoc->param_flags =
@@ -3478,6 +3479,56 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
 }
 
 
+/*
+ * SCTP_PEER_ADDR_THLDS
+ *
+ * This option allows us to alter the partially failed threshold for one or all
+ * transports in an association.  See Section 6.1 of:
+ * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt
+ */
+static int sctp_setsockopt_paddr_thresholds(struct sock *sk,
+                                           char __user *optval,
+                                           unsigned int optlen)
+{
+       struct sctp_paddrthlds val;
+       struct sctp_transport *trans;
+       struct sctp_association *asoc;
+
+       if (optlen < sizeof(struct sctp_paddrthlds))
+               return -EINVAL;
+       if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval,
+                          sizeof(struct sctp_paddrthlds)))
+               return -EFAULT;
+
+
+       if (sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) {
+               asoc = sctp_id2assoc(sk, val.spt_assoc_id);
+               if (!asoc)
+                       return -ENOENT;
+               list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+                                   transports) {
+                       if (val.spt_pathmaxrxt)
+                               trans->pathmaxrxt = val.spt_pathmaxrxt;
+                       trans->pf_retrans = val.spt_pathpfthld;
+               }
+
+               if (val.spt_pathmaxrxt)
+                       asoc->pathmaxrxt = val.spt_pathmaxrxt;
+               asoc->pf_retrans = val.spt_pathpfthld;
+       } else {
+               trans = sctp_addr_id2transport(sk, &val.spt_address,
+                                              val.spt_assoc_id);
+               if (!trans)
+                       return -ENOENT;
+
+               if (val.spt_pathmaxrxt)
+                       trans->pathmaxrxt = val.spt_pathmaxrxt;
+               trans->pf_retrans = val.spt_pathpfthld;
+       }
+
+       return 0;
+}
+
 /* API 6.2 setsockopt(), getsockopt()
  *
  * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -3627,6 +3678,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
        case SCTP_AUTO_ASCONF:
                retval = sctp_setsockopt_auto_asconf(sk, optval, optlen);
                break;
+       case SCTP_PEER_ADDR_THLDS:
+               retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -4223,6 +4277,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
 {
        sctp_peeloff_arg_t peeloff;
        struct socket *newsock;
+       struct file *newfile;
        int retval = 0;
 
        if (len < sizeof(sctp_peeloff_arg_t))
@@ -4236,22 +4291,35 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
                goto out;
 
        /* Map the socket to an unused fd that can be returned to the user.  */
-       retval = sock_map_fd(newsock, 0);
+       retval = get_unused_fd();
        if (retval < 0) {
                sock_release(newsock);
                goto out;
        }
 
+       newfile = sock_alloc_file(newsock, 0);
+       if (unlikely(IS_ERR(newfile))) {
+               put_unused_fd(retval);
+               sock_release(newsock);
+               return PTR_ERR(newfile);
+       }
+
        SCTP_DEBUG_PRINTK("%s: sk: %p newsk: %p sd: %d\n",
                          __func__, sk, newsock->sk, retval);
 
        /* Return the fd mapped to the new socket.  */
+       if (put_user(len, optlen)) {
+               fput(newfile);
+               put_unused_fd(retval);
+               return -EFAULT;
+       }
        peeloff.sd = retval;
-       if (put_user(len, optlen))
+       if (copy_to_user(optval, &peeloff, len)) {
+               fput(newfile);
+               put_unused_fd(retval);
                return -EFAULT;
-       if (copy_to_user(optval, &peeloff, len))
-               retval = -EFAULT;
-
+       }
+       fd_install(retval, newfile);
 out:
        return retval;
 }
@@ -5498,6 +5566,51 @@ static int sctp_getsockopt_assoc_ids(struct sock *sk, int len,
        return 0;
 }
 
+/*
+ * SCTP_PEER_ADDR_THLDS
+ *
+ * This option allows us to fetch the partially failed threshold for one or all
+ * transports in an association.  See Section 6.1 of:
+ * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt
+ */
+static int sctp_getsockopt_paddr_thresholds(struct sock *sk,
+                                           char __user *optval,
+                                           int len,
+                                           int __user *optlen)
+{
+       struct sctp_paddrthlds val;
+       struct sctp_transport *trans;
+       struct sctp_association *asoc;
+
+       if (len < sizeof(struct sctp_paddrthlds))
+               return -EINVAL;
+       len = sizeof(struct sctp_paddrthlds);
+       if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval, len))
+               return -EFAULT;
+
+       if (sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) {
+               asoc = sctp_id2assoc(sk, val.spt_assoc_id);
+               if (!asoc)
+                       return -ENOENT;
+
+               val.spt_pathpfthld = asoc->pf_retrans;
+               val.spt_pathmaxrxt = asoc->pathmaxrxt;
+       } else {
+               trans = sctp_addr_id2transport(sk, &val.spt_address,
+                                              val.spt_assoc_id);
+               if (!trans)
+                       return -ENOENT;
+
+               val.spt_pathmaxrxt = trans->pathmaxrxt;
+               val.spt_pathpfthld = trans->pf_retrans;
+       }
+
+       if (put_user(len, optlen) || copy_to_user(optval, &val, len))
+               return -EFAULT;
+
+       return 0;
+}
+
 SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                                char __user *optval, int __user *optlen)
 {
@@ -5636,6 +5749,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
        case SCTP_AUTO_ASCONF:
                retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen);
                break;
+       case SCTP_PEER_ADDR_THLDS:
+               retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;