]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/sctp/socket.c
Merge branch 'for-linus' of git://brick.kernel.dk/data/git/linux-2.6-block
[mv-sheeva.git] / net / sctp / socket.c
index adbe531fdedc5f32572cfee42b362a989e8ee2c9..bdd8bd428b64f3de8ae4fff0c9414fce324ddf30 100644 (file)
@@ -107,7 +107,7 @@ static void sctp_sock_migrate(struct sock *, struct sock *,
                              struct sctp_association *, sctp_socket_type_t);
 static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;
 
-extern kmem_cache_t *sctp_bucket_cachep;
+extern struct kmem_cache *sctp_bucket_cachep;
 
 /* Get the sndbuf space available at the time on the association.  */
 static inline int sctp_wspace(struct sctp_association *asoc)
@@ -1000,7 +1000,6 @@ static int __sctp_connect(struct sock* sk,
                        goto out_free;
 
                memcpy(&to, sa_addr, af->sockaddr_len);
-               to.v4.sin_port = ntohs(to.v4.sin_port);
 
                /* Check if there already is a matching association on the
                 * endpoint (other than the one created here).
@@ -1049,7 +1048,7 @@ static int __sctp_connect(struct sock* sk,
                                }
                        }
 
-                       scope = sctp_scope(&to);
+                       scope = sctp_scope(sa_addr);
                        asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);
                        if (!asoc) {
                                err = -ENOMEM;
@@ -1357,7 +1356,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        struct sctp_association *new_asoc=NULL, *asoc=NULL;
        struct sctp_transport *transport, *chunk_tp;
        struct sctp_chunk *chunk;
-       union sctp_addr to, tmp;
+       union sctp_addr to;
        struct sockaddr *msg_name = NULL;
        struct sctp_sndrcvinfo default_sinfo = { 0 };
        struct sctp_sndrcvinfo *sinfo;
@@ -1411,12 +1410,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                if (msg_namelen > sizeof(to))
                        msg_namelen = sizeof(to);
                memcpy(&to, msg->msg_name, msg_namelen);
-               memcpy(&tmp, msg->msg_name, msg_namelen);
-               SCTP_DEBUG_PRINTK("Just memcpy'd. msg_name is "
-                                 "0x%x:%u.\n",
-                                 to.v4.sin_addr.s_addr, to.v4.sin_port);
-
-               to.v4.sin_port = ntohs(to.v4.sin_port);
                msg_name = msg->msg_name;
        }
 
@@ -1466,7 +1459,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        /* If a msg_name has been specified, assume this is to be used.  */
        if (msg_name) {
                /* Look for a matching association on the endpoint. */
-               asoc = sctp_endpoint_lookup_assoc(ep, &tmp, &transport);
+               asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport);
                if (!asoc) {
                        /* If we could not find a matching association on the
                         * endpoint, make sure that it is not a TCP-style
@@ -1475,7 +1468,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                         */
                        if ((sctp_style(sk, TCP) &&
                             sctp_sstate(sk, ESTABLISHED)) ||
-                           sctp_endpoint_is_peeled_off(ep, &tmp)) {
+                           sctp_endpoint_is_peeled_off(ep, &to)) {
                                err = -EADDRNOTAVAIL;
                                goto out_unlock;
                        }
@@ -1612,7 +1605,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                }
 
                /* Prime the peer's transport structures.  */
-               transport = sctp_assoc_add_peer(asoc, &tmp, GFP_KERNEL, SCTP_UNKNOWN);
+               transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL, SCTP_UNKNOWN);
                if (!transport) {
                        err = -ENOMEM;
                        goto out_free;
@@ -1679,7 +1672,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
         */
        if ((sctp_style(sk, TCP) && msg_name) ||
            (sinfo_flags & SCTP_ADDR_OVER)) {
-               chunk_tp = sctp_assoc_lookup_paddr(asoc, &tmp);
+               chunk_tp = sctp_assoc_lookup_paddr(asoc, &to);
                if (!chunk_tp) {
                        err = -EINVAL;
                        goto out_free;
@@ -2753,6 +2746,46 @@ static int sctp_setsockopt_adaption_layer(struct sock *sk, char __user *optval,
        return 0;
 }
 
+/*
+ * 7.1.29.  Set or Get the default context (SCTP_CONTEXT)
+ *
+ * The context field in the sctp_sndrcvinfo structure is normally only
+ * used when a failed message is retrieved holding the value that was
+ * sent down on the actual send call.  This option allows the setting of
+ * a default context on an association basis that will be received on
+ * reading messages from the peer.  This is especially helpful in the
+ * one-2-many model for an application to keep some reference to an
+ * internal state machine that is processing messages on the
+ * association.  Note that the setting of this value only effects
+ * received messages from the peer and does not effect the value that is
+ * saved with outbound messages.
+ */
+static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
+                                  int optlen)
+{
+       struct sctp_assoc_value params;
+       struct sctp_sock *sp;
+       struct sctp_association *asoc;
+
+       if (optlen != sizeof(struct sctp_assoc_value))
+               return -EINVAL;
+       if (copy_from_user(&params, optval, optlen))
+               return -EFAULT;
+
+       sp = sctp_sk(sk);
+
+       if (params.assoc_id != 0) {
+               asoc = sctp_id2assoc(sk, params.assoc_id);
+               if (!asoc)
+                       return -EINVAL;
+               asoc->default_rcv_context = params.assoc_value;
+       } else {
+               sp->default_rcv_context = params.assoc_value;
+       }
+
+       return 0;
+}
+
 /* API 6.2 setsockopt(), getsockopt()
  *
  * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -2864,6 +2897,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
        case SCTP_ADAPTION_LAYER:
                retval = sctp_setsockopt_adaption_layer(sk, optval, optlen);
                break;
+       case SCTP_CONTEXT:
+               retval = sctp_setsockopt_context(sk, optval, optlen);
+               break;
 
        default:
                retval = -ENOPROTOOPT;
@@ -3023,6 +3059,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        sp->default_context = 0;
        sp->default_timetolive = 0;
 
+       sp->default_rcv_context = 0;
+
        /* Initialize default setup parameters. These parameters
         * can be modified with the SCTP_INITMSG socket option or
         * overridden by the SCTP_INIT CMSG.
@@ -3828,10 +3866,9 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
        sctp_assoc_t id;
        struct sctp_bind_addr *bp;
        struct sctp_association *asoc;
-       struct list_head *pos;
+       struct list_head *pos, *temp;
        struct sctp_sockaddr_entry *addr;
        rwlock_t *addr_lock;
-       unsigned long flags;
        int cnt = 0;
 
        if (len != sizeof(sctp_assoc_t))
@@ -3866,8 +3903,7 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
                addr = list_entry(bp->address_list.next,
                                  struct sctp_sockaddr_entry, list);
                if (sctp_is_any(&addr->a)) {
-                       sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
-                       list_for_each(pos, &sctp_local_addr_list) {
+                       list_for_each_safe(pos, temp, &sctp_local_addr_list) {
                                addr = list_entry(pos,
                                                  struct sctp_sockaddr_entry,
                                                  list);
@@ -3876,8 +3912,6 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
                                        continue;
                                cnt++;
                        }
-                       sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
-                                                   flags);
                } else {
                        cnt = 1;
                }
@@ -3899,15 +3933,13 @@ done:
 static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs,
                                        void __user *to)
 {
-       struct list_head *pos;
+       struct list_head *pos, *next;
        struct sctp_sockaddr_entry *addr;
-       unsigned long flags;
        union sctp_addr temp;
        int cnt = 0;
        int addrlen;
 
-       sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
-       list_for_each(pos, &sctp_local_addr_list) {
+       list_for_each_safe(pos, next, &sctp_local_addr_list) {
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
                if ((PF_INET == sk->sk_family) && 
                    (AF_INET6 == addr->a.sa.sa_family))
@@ -3916,16 +3948,13 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
                                                                &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
-               if (copy_to_user(to, &temp, addrlen)) {
-                       sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
-                                                   flags);
+               if (copy_to_user(to, &temp, addrlen))
                        return -EFAULT;
-               }
+
                to += addrlen;
                cnt ++;
                if (cnt >= max_addrs) break;
        }
-       sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
 
        return cnt;
 }
@@ -3933,15 +3962,13 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
 static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
                                    void __user **to, size_t space_left)
 {
-       struct list_head *pos;
+       struct list_head *pos, *next;
        struct sctp_sockaddr_entry *addr;
-       unsigned long flags;
        union sctp_addr temp;
        int cnt = 0;
        int addrlen;
 
-       sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
-       list_for_each(pos, &sctp_local_addr_list) {
+       list_for_each_safe(pos, next, &sctp_local_addr_list) {
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
                if ((PF_INET == sk->sk_family) && 
                    (AF_INET6 == addr->a.sa.sa_family))
@@ -3952,16 +3979,13 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
                if(space_left<addrlen)
                        return -ENOMEM;
-               if (copy_to_user(*to, &temp, addrlen)) {
-                       sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
-                                                   flags);
+               if (copy_to_user(*to, &temp, addrlen))
                        return -EFAULT;
-               }
+
                *to += addrlen;
                cnt ++;
                space_left -= addrlen;
        }
-       sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
 
        return cnt;
 }
@@ -4441,6 +4465,42 @@ static int sctp_getsockopt_mappedv4(struct sock *sk, int len,
        return 0;
 }
 
+/*
+ * 7.1.29.  Set or Get the default context (SCTP_CONTEXT)
+ * (chapter and verse is quoted at sctp_setsockopt_context())
+ */
+static int sctp_getsockopt_context(struct sock *sk, int len,
+                                  char __user *optval, int __user *optlen)
+{
+       struct sctp_assoc_value params;
+       struct sctp_sock *sp;
+       struct sctp_association *asoc;
+
+       if (len != sizeof(struct sctp_assoc_value))
+               return -EINVAL;
+
+       if (copy_from_user(&params, optval, len))
+               return -EFAULT;
+
+       sp = sctp_sk(sk);
+
+       if (params.assoc_id != 0) {
+               asoc = sctp_id2assoc(sk, params.assoc_id);
+               if (!asoc)
+                       return -EINVAL;
+               params.assoc_value = asoc->default_rcv_context;
+       } else {
+               params.assoc_value = sp->default_rcv_context;
+       }
+
+       if (put_user(len, optlen))
+               return -EFAULT;
+       if (copy_to_user(optval, &params, len))
+               return -EFAULT;
+
+       return 0;
+}
+
 /*
  * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
  *
@@ -4579,6 +4639,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_adaption_layer(sk, len, optval,
                                                        optlen);
                break;
+       case SCTP_CONTEXT:
+               retval = sctp_getsockopt_context(sk, len, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -4996,7 +5059,7 @@ static struct sctp_bind_bucket *sctp_bucket_create(
 {
        struct sctp_bind_bucket *pp;
 
-       pp = kmem_cache_alloc(sctp_bucket_cachep, SLAB_ATOMIC);
+       pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC);
        SCTP_DBG_OBJCNT_INC(bind_bucket);
        if (pp) {
                pp->port = snum;
@@ -5055,7 +5118,7 @@ static int sctp_autobind(struct sock *sk)
 {
        union sctp_addr autoaddr;
        struct sctp_af *af;
-       unsigned short port;
+       __be16 port;
 
        /* Initialize a local sockaddr structure to INADDR_ANY. */
        af = sctp_sk(sk)->pf->af;