OSDN Git Service

Merge branches 'devel', 'devel-stable' and 'fixes' into for-linus
[android-x86/kernel.git] / net / sctp / socket.c
index deb82e3..6766913 100644 (file)
@@ -658,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
@@ -1492,7 +1496,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;
@@ -1756,6 +1760,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;
@@ -1786,12 +1791,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);
@@ -2283,7 +2286,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) {
@@ -3215,14 +3218,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 ||
@@ -3257,14 +3255,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;
@@ -5283,6 +5276,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)
 {
@@ -5415,6 +5457,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;