]> err.no Git - linux-2.6/blobdiff - net/sctp/socket.c
ipv6: Fix OOPS, ip -f inet6 route get fec0::1, linux-2.6.26, ip6_route_output, rt6_fi...
[linux-2.6] / net / sctp / socket.c
index a0e879bb202dcb1ad5b0e9a042c03e37daf25b6b..dbb79adf8f3c0bab606f7141e96ae96dd29b3e4c 100644 (file)
@@ -377,18 +377,19 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
        if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
                return -EACCES;
 
+       /* See if the address matches any of the addresses we may have
+        * already bound before checking against other endpoints.
+        */
+       if (sctp_bind_addr_match(bp, addr, sp))
+               return -EINVAL;
+
        /* Make sure we are allowed to bind here.
         * The function sctp_get_port_local() does duplicate address
         * detection.
         */
        addr->v4.sin_port = htons(snum);
        if ((ret = sctp_get_port_local(sk, addr))) {
-               if (ret == (long) sk) {
-                       /* This endpoint has a conflicting address. */
-                       return -EINVAL;
-               } else {
-                       return -EADDRINUSE;
-               }
+               return -EADDRINUSE;
        }
 
        /* Refresh ephemeral port.  */
@@ -3909,7 +3910,7 @@ 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);
+       retval = sock_map_fd(newsock, 0);
        if (retval < 0) {
                sock_release(newsock);
                goto out;
@@ -5584,8 +5585,9 @@ pp_found:
                        struct sctp_endpoint *ep2;
                        ep2 = sctp_sk(sk2)->ep;
 
-                       if (reuse && sk2->sk_reuse &&
-                           sk2->sk_state != SCTP_SS_LISTENING)
+                       if (sk == sk2 ||
+                           (reuse && sk2->sk_reuse &&
+                            sk2->sk_state != SCTP_SS_LISTENING))
                                continue;
 
                        if (sctp_bind_addr_conflict(&ep2->base.bind_addr, addr,
@@ -5702,8 +5704,13 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
        if (!ep->base.bind_addr.port) {
                if (sctp_autobind(sk))
                        return -EAGAIN;
-       } else
+       } else {
+               if (sctp_get_port(sk, inet_sk(sk)->num)) {
+                       sk->sk_state = SCTP_SS_CLOSED;
+                       return -EADDRINUSE;
+               }
                sctp_sk(sk)->bind_hash->fastreuse = 0;
+       }
 
        sctp_hash_endpoint(ep);
        return 0;
@@ -5773,7 +5780,7 @@ int sctp_inet_listen(struct socket *sock, int backlog)
                goto out;
 
        /* Allocate HMAC for generating cookie. */
-       if (sctp_hmac_alg) {
+       if (!sctp_sk(sk)->hmac && sctp_hmac_alg) {
                tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
                if (IS_ERR(tfm)) {
                        if (net_ratelimit()) {
@@ -5801,7 +5808,8 @@ int sctp_inet_listen(struct socket *sock, int backlog)
                goto cleanup;
 
        /* Store away the transform reference. */
-       sctp_sk(sk)->hmac = tfm;
+       if (!sctp_sk(sk)->hmac)
+               sctp_sk(sk)->hmac = tfm;
 out:
        sctp_release_sock(sk);
        return err;