]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/sctp/socket.c
flag parameters: socket and socketpair
[linux-2.6-omap-h63xx.git] / net / sctp / socket.c
index 43460a1cb6d0ce4b24205d5df33d1b36af9d3e62..dbb79adf8f3c0bab606f7141e96ae96dd29b3e4c 100644 (file)
@@ -116,7 +116,7 @@ static int sctp_memory_pressure;
 static atomic_t sctp_memory_allocated;
 static atomic_t sctp_sockets_allocated;
 
-static void sctp_enter_memory_pressure(void)
+static void sctp_enter_memory_pressure(struct sock *sk)
 {
        sctp_memory_pressure = 1;
 }
@@ -308,9 +308,16 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
        if (len < sizeof (struct sockaddr))
                return NULL;
 
-       /* Does this PF support this AF? */
-       if (!opt->pf->af_supported(addr->sa.sa_family, opt))
-               return NULL;
+       /* V4 mapped address are really of AF_INET family */
+       if (addr->sa.sa_family == AF_INET6 &&
+           ipv6_addr_v4mapped(&addr->v6.sin6_addr)) {
+               if (!opt->pf->af_supported(AF_INET, opt))
+                       return NULL;
+       } else {
+               /* Does this PF support this AF? */
+               if (!opt->pf->af_supported(addr->sa.sa_family, opt))
+                       return NULL;
+       }
 
        /* If we get this far, af is valid. */
        af = sctp_get_af_specific(addr->sa.sa_family);
@@ -370,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.  */
@@ -3902,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;
@@ -4223,6 +4231,8 @@ static int sctp_getsockopt_peer_addrs_num_old(struct sock *sk, int len,
        if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
                return -EFAULT;
 
+       printk(KERN_WARNING "SCTP: Use of SCTP_GET_PEER_ADDRS_NUM_OLD "
+                           "socket option deprecated\n");
        /* For UDP-style sockets, id specifies the association to query.  */
        asoc = sctp_id2assoc(sk, id);
        if (!asoc)
@@ -4262,6 +4272,9 @@ static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len,
 
        if (getaddrs.addr_num <= 0) return -EINVAL;
 
+       printk(KERN_WARNING "SCTP: Use of SCTP_GET_PEER_ADDRS_OLD "
+                           "socket option deprecated\n");
+
        /* For UDP-style sockets, id specifies the association to query.  */
        asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
        if (!asoc)
@@ -4355,6 +4368,9 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
        if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
                return -EFAULT;
 
+       printk(KERN_WARNING "SCTP: Use of SCTP_GET_LOCAL_ADDRS_NUM_OLD "
+                           "socket option deprecated\n");
+
        /*
         *  For UDP-style sockets, id specifies the association to query.
         *  If the id field is set to the value '0' then the locally bound
@@ -4387,6 +4403,11 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
                                    (AF_INET6 == addr->a.sa.sa_family))
                                        continue;
 
+                               if ((PF_INET6 == sk->sk_family) &&
+                                   inet_v6_ipv6only(sk) &&
+                                   (AF_INET == addr->a.sa.sa_family))
+                                       continue;
+
                                cnt++;
                        }
                        rcu_read_unlock();
@@ -4427,6 +4448,10 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
                if ((PF_INET == sk->sk_family) &&
                    (AF_INET6 == addr->a.sa.sa_family))
                        continue;
+               if ((PF_INET6 == sk->sk_family) &&
+                   inet_v6_ipv6only(sk) &&
+                   (AF_INET == addr->a.sa.sa_family))
+                       continue;
                memcpy(&temp, &addr->a, sizeof(temp));
                if (!temp.v4.sin_port)
                        temp.v4.sin_port = htons(port);
@@ -4462,6 +4487,10 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
                if ((PF_INET == sk->sk_family) &&
                    (AF_INET6 == addr->a.sa.sa_family))
                        continue;
+               if ((PF_INET6 == sk->sk_family) &&
+                   inet_v6_ipv6only(sk) &&
+                   (AF_INET == addr->a.sa.sa_family))
+                       continue;
                memcpy(&temp, &addr->a, sizeof(temp));
                if (!temp.v4.sin_port)
                        temp.v4.sin_port = htons(port);
@@ -4515,6 +4544,10 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
        if (getaddrs.addr_num <= 0 ||
            getaddrs.addr_num >= (INT_MAX / sizeof(union sctp_addr)))
                return -EINVAL;
+
+       printk(KERN_WARNING "SCTP: Use of SCTP_GET_LOCAL_ADDRS_OLD "
+                           "socket option deprecated\n");
+
        /*
         *  For UDP-style sockets, id specifies the association to query.
         *  If the id field is set to the value '0' then the locally bound
@@ -5552,12 +5585,13 @@ 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_match(&ep2->base.bind_addr, addr,
-                                                sctp_sk(sk))) {
+                       if (sctp_bind_addr_conflict(&ep2->base.bind_addr, addr,
+                                                sctp_sk(sk2), sctp_sk(sk))) {
                                ret = (long)sk2;
                                goto fail_unlock;
                        }
@@ -5670,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;
@@ -5741,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()) {
@@ -5769,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;