X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=net%2Fsctp%2Fsocket.c;h=b811691c35bf4eba764efa3eba3b0daeac6eca64;hb=50aa4eb0b978f4a0283471c776ed812269ac8af5;hp=b6e4b89539b3178216037c53350f5591dde8a1b6;hpb=be9bf30c73184e0f1e4e0a50fb193d2a551bf75e;p=mv-sheeva.git diff --git a/net/sctp/socket.c b/net/sctp/socket.c index b6e4b89539b..b811691c35b 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -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. */