]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/sctp/socket.c
[PATCH] ufs: i_blocks wrong count
[mv-sheeva.git] / net / sctp / socket.c
index b6e4b89539b3178216037c53350f5591dde8a1b6..b811691c35bf4eba764efa3eba3b0daeac6eca64 100644 (file)
@@ -172,7 +172,7 @@ static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
                return -EINVAL;
 
        /* Is this a valid SCTP address?  */
-       if (!af->addr_valid(addr, sctp_sk(sk)))
+       if (!af->addr_valid(addr, sctp_sk(sk), NULL))
                return -EINVAL;
 
        if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr)))
@@ -1057,6 +1057,7 @@ static int __sctp_connect(struct sock* sk,
        inet_sk(sk)->dport = htons(asoc->peer.port);
        af = sctp_get_af_specific(to.sa.sa_family);
        af->to_sk_daddr(&to, sk);
+       sk->sk_err = 0;
 
        timeo = sock_sndtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK);
        err = sctp_wait_for_connect(asoc, &timeo);
@@ -1228,7 +1229,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
 
        ep = sctp_sk(sk)->ep;
 
-       /* Walk all associations on a socket, not on an endpoint.  */
+       /* Walk all associations on an endpoint.  */
        list_for_each_safe(pos, temp, &ep->asocs) {
                asoc = list_entry(pos, struct sctp_association, asocs);
 
@@ -1241,13 +1242,13 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
                        if (sctp_state(asoc, CLOSED)) {
                                sctp_unhash_established(asoc);
                                sctp_association_free(asoc);
+                               continue;
+                       }
+               }
 
-                       } else if (sock_flag(sk, SOCK_LINGER) &&
-                                  !sk->sk_lingertime)
-                               sctp_primitive_ABORT(asoc, NULL);
-                       else
-                               sctp_primitive_SHUTDOWN(asoc, NULL);
-               } else
+               if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)
+                       sctp_primitive_ABORT(asoc, NULL);
+               else
                        sctp_primitive_SHUTDOWN(asoc, NULL);
        }
 
@@ -2529,8 +2530,32 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int o
 
        /* Set the values to the specific association */
        if (asoc) {
-               if (assocparams.sasoc_asocmaxrxt != 0)
+               if (assocparams.sasoc_asocmaxrxt != 0) {
+                       __u32 path_sum = 0;
+                       int   paths = 0;
+                       struct list_head *pos;
+                       struct sctp_transport *peer_addr;
+
+                       list_for_each(pos, &asoc->peer.transport_addr_list) {
+                               peer_addr = list_entry(pos,
+                                               struct sctp_transport,
+                                               transports);
+                               path_sum += peer_addr->pathmaxrxt;
+                               paths++;
+                       }
+
+                       /* Only validate asocmaxrxt if we have more then
+                        * one path/transport.  We do this because path
+                        * retransmissions are only counted when we have more
+                        * then one path.
+                        */
+                       if (paths > 1 &&
+                           assocparams.sasoc_asocmaxrxt > path_sum)
+                               return -EINVAL;
+
                        asoc->max_retrans = assocparams.sasoc_asocmaxrxt;
+               }
+
                if (assocparams.sasoc_cookie_life != 0) {
                        asoc->cookie_life.tv_sec =
                                        assocparams.sasoc_cookie_life / 1000;
@@ -5317,6 +5342,7 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
                 */
                sctp_release_sock(sk);
                current_timeo = schedule_timeout(current_timeo);
+               BUG_ON(sk != asoc->base.sk);
                sctp_lock_sock(sk);
 
                *timeo_p = current_timeo;
@@ -5604,12 +5630,14 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
         */
        newsp->type = type;
 
-       spin_lock_bh(&oldsk->sk_lock.slock);
-       /* Migrate the backlog from oldsk to newsk. */
-       sctp_backlog_migrate(assoc, oldsk, newsk);
-       /* Migrate the association to the new socket. */
+       /* Mark the new socket "in-use" by the user so that any packets
+        * that may arrive on the association after we've moved it are
+        * queued to the backlog.  This prevents a potential race between
+        * backlog processing on the old socket and new-packet processing
+        * on the new socket.
+        */
+       sctp_lock_sock(newsk);
        sctp_assoc_migrate(assoc, newsk);
-       spin_unlock_bh(&oldsk->sk_lock.slock);
 
        /* If the association on the newsk is already closed before accept()
         * is called, set RCV_SHUTDOWN flag.
@@ -5618,6 +5646,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
                newsk->sk_shutdown |= RCV_SHUTDOWN;
 
        newsk->sk_state = SCTP_SS_ESTABLISHED;
+       sctp_release_sock(newsk);
 }
 
 /* This proto struct describes the ULP interface for SCTP.  */