Merge ../linux-2.6-watchdog-mm
[pandora-kernel.git] / net / sctp / socket.c
index e03ba90..388d0fb 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)
@@ -228,11 +228,9 @@ static struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
        struct sctp_association *addr_asoc = NULL, *id_asoc = NULL;
        struct sctp_transport *transport;
        union sctp_addr *laddr = (union sctp_addr *)addr;
-       union sctp_addr tmp;
 
-       flip_to_h(&tmp, laddr);
        addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep,
-                                              &tmp,
+                                              laddr,
                                               &transport);
 
        if (!addr_asoc)
@@ -313,7 +311,6 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
        struct sctp_af *af;
        unsigned short snum;
        int ret = 0;
-       union sctp_addr tmp;
 
        /* Common sockaddr verification. */
        af = sctp_sockaddr_af(sp, addr, len);
@@ -369,8 +366,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
        sctp_write_lock(&ep->base.addr_lock);
 
        /* Use GFP_ATOMIC since BHs are disabled.  */
-       flip_to_h(&tmp, addr);
-       ret = sctp_add_bind_addr(bp, &tmp, 1, GFP_ATOMIC);
+       ret = sctp_add_bind_addr(bp, addr, 1, GFP_ATOMIC);
        sctp_write_unlock(&ep->base.addr_lock);
        sctp_local_bh_enable();
 
@@ -551,7 +547,7 @@ static int sctp_send_asconf_add_ip(struct sock              *sk,
                laddr = list_entry(p, struct sctp_sockaddr_entry, list);
                sctp_read_unlock(&asoc->base.addr_lock);
 
-               chunk = sctp_make_asconf_update_ip(asoc, &laddr->a_h, addrs,
+               chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs,
                                                   addrcnt, SCTP_PARAM_ADD_IP);
                if (!chunk) {
                        retval = -ENOMEM;
@@ -572,7 +568,6 @@ static int sctp_send_asconf_add_ip(struct sock              *sk,
                        addr = (union sctp_addr *)addr_buf;
                        af = sctp_get_af_specific(addr->v4.sin_family);
                        memcpy(&saveaddr, addr, af->sockaddr_len);
-                       saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port);
                        retval = sctp_add_bind_addr(bp, &saveaddr, 0,
                                                    GFP_ATOMIC);
                        addr_buf += af->sockaddr_len;
@@ -607,9 +602,8 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
        int cnt;
        struct sctp_bind_addr *bp = &ep->base.bind_addr;
        int retval = 0;
-       union sctp_addr saveaddr;
        void *addr_buf;
-       struct sockaddr *sa_addr;
+       union sctp_addr *sa_addr;
        struct sctp_af *af;
 
        SCTP_DEBUG_PRINTK("sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)\n",
@@ -627,19 +621,13 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
                        goto err_bindx_rem;
                }
 
-               /* The list may contain either IPv4 or IPv6 address;
-                * determine the address length to copy the address to
-                * saveaddr. 
-                */
-               sa_addr = (struct sockaddr *)addr_buf;
-               af = sctp_get_af_specific(sa_addr->sa_family);
+               sa_addr = (union sctp_addr *)addr_buf;
+               af = sctp_get_af_specific(sa_addr->sa.sa_family);
                if (!af) {
                        retval = -EINVAL;
                        goto err_bindx_rem;
                }
-               memcpy(&saveaddr, sa_addr, af->sockaddr_len); 
-               saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port);
-               if (saveaddr.v4.sin_port != bp->port) {
+               if (sa_addr->v4.sin_port != htons(bp->port)) {
                        retval = -EINVAL;
                        goto err_bindx_rem;
                }
@@ -654,7 +642,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
                sctp_local_bh_disable();
                sctp_write_lock(&ep->base.addr_lock);
 
-               retval = sctp_del_bind_addr(bp, &saveaddr);
+               retval = sctp_del_bind_addr(bp, sa_addr);
 
                sctp_write_unlock(&ep->base.addr_lock);
                sctp_local_bh_enable();
@@ -976,7 +964,7 @@ static int __sctp_connect(struct sock* sk,
        int err = 0;
        int addrcnt = 0;
        int walk_size = 0;
-       struct sockaddr *sa_addr;
+       union sctp_addr *sa_addr;
        void *addr_buf;
 
        sp = sctp_sk(sk);
@@ -996,8 +984,8 @@ static int __sctp_connect(struct sock* sk,
        /* Walk through the addrs buffer and count the number of addresses. */
        addr_buf = kaddrs;
        while (walk_size < addrs_size) {
-               sa_addr = (struct sockaddr *)addr_buf;
-               af = sctp_get_af_specific(sa_addr->sa_family);
+               sa_addr = (union sctp_addr *)addr_buf;
+               af = sctp_get_af_specific(sa_addr->sa.sa_family);
 
                /* If the address family is not supported or if this address
                 * causes the address buffer to overflow return EINVAL.
@@ -1007,18 +995,16 @@ static int __sctp_connect(struct sock* sk,
                        goto out_free;
                }
 
-               err = sctp_verify_addr(sk, (union sctp_addr *)sa_addr,
-                                      af->sockaddr_len);
+               err = sctp_verify_addr(sk, sa_addr, af->sockaddr_len);
                if (err)
                        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).
                 */
-               asoc2 = sctp_endpoint_lookup_assoc(ep, &to, &transport);
+               asoc2 = sctp_endpoint_lookup_assoc(ep, sa_addr, &transport);
                if (asoc2 && asoc2 != asoc) {
                        if (asoc2->state >= SCTP_STATE_ESTABLISHED)
                                err = -EISCONN;
@@ -1031,7 +1017,7 @@ static int __sctp_connect(struct sock* sk,
                 * make sure that there is no peeled-off association matching
                 * the peer address even on another socket.
                 */
-               if (sctp_endpoint_is_peeled_off(ep, &to)) {
+               if (sctp_endpoint_is_peeled_off(ep, sa_addr)) {
                        err = -EADDRNOTAVAIL;
                        goto out_free;
                }
@@ -1062,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;
@@ -1071,7 +1057,7 @@ static int __sctp_connect(struct sock* sk,
                }
 
                /* Prime the peer's transport structures.  */
-               transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL,
+               transport = sctp_assoc_add_peer(asoc, sa_addr, GFP_KERNEL,
                                                SCTP_UNKNOWN);
                if (!transport) {
                        err = -ENOMEM;
@@ -1424,11 +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);
-               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;
        }
 
@@ -2750,17 +2731,57 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
        return err;
 }
 
-static int sctp_setsockopt_adaption_layer(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval,
                                          int optlen)
 {
-       struct sctp_setadaption adaption;
+       struct sctp_setadaptation adaptation;
+
+       if (optlen != sizeof(struct sctp_setadaptation))
+               return -EINVAL;
+       if (copy_from_user(&adaptation, optval, optlen))
+               return -EFAULT;
+
+       sctp_sk(sk)->adaptation_ind = adaptation.ssb_adaptation_ind;
+
+       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_setadaption))
+       if (optlen != sizeof(struct sctp_assoc_value))
                return -EINVAL;
-       if (copy_from_user(&adaption, optval, optlen)) 
+       if (copy_from_user(&params, optval, optlen))
                return -EFAULT;
 
-       sctp_sk(sk)->adaption_ind = adaption.ssb_adaption_ind;
+       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;
 }
@@ -2873,8 +2894,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
        case SCTP_MAXSEG:
                retval = sctp_setsockopt_maxseg(sk, optval, optlen);
                break;
-       case SCTP_ADAPTION_LAYER:
-               retval = sctp_setsockopt_adaption_layer(sk, optval, optlen);
+       case SCTP_ADAPTATION_LAYER:
+               retval = sctp_setsockopt_adaptation_layer(sk, optval, optlen);
+               break;
+       case SCTP_CONTEXT:
+               retval = sctp_setsockopt_context(sk, optval, optlen);
                break;
 
        default:
@@ -3035,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.
@@ -3097,7 +3123,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        /* User specified fragmentation limit. */
        sp->user_frag         = 0;
 
-       sp->adaption_ind = 0;
+       sp->adaptation_ind = 0;
 
        sp->pf = sctp_get_pf_specific(sk->sk_family);
 
@@ -3214,8 +3240,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
        status.sstat_outstrms = asoc->c.sinit_num_ostreams;
        status.sstat_fragmentation_point = asoc->frag_point;
        status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
-       flip_to_n((union sctp_addr *)&status.sstat_primary.spinfo_address,
-              &transport->ipaddr_h);
+       memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr,
+                       transport->af_specific->sockaddr_len);
        /* Map ipv4 address into v4-mapped-on-v6 address.  */
        sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
                (union sctp_addr *)&status.sstat_primary.spinfo_address);
@@ -3764,10 +3790,9 @@ static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len,
        to = (void __user *)getaddrs.addrs;
        list_for_each(pos, &asoc->peer.transport_addr_list) {
                from = list_entry(pos, struct sctp_transport, transports);
-               memcpy(&temp, &from->ipaddr_h, sizeof(temp));
+               memcpy(&temp, &from->ipaddr, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
                addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
-               temp.v4.sin_port = htons(temp.v4.sin_port);
                if (copy_to_user(to, &temp, addrlen))
                        return -EFAULT;
                to += addrlen ;
@@ -3813,12 +3838,11 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
 
        list_for_each(pos, &asoc->peer.transport_addr_list) {
                from = list_entry(pos, struct sctp_transport, transports);
-               memcpy(&temp, &from->ipaddr_h, sizeof(temp));
+               memcpy(&temp, &from->ipaddr, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
                addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
                if(space_left < addrlen)
                        return -ENOMEM;
-               temp.v4.sin_port = htons(temp.v4.sin_port);
                if (copy_to_user(to, &temp, addrlen))
                        return -EFAULT;
                to += addrlen;
@@ -3842,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))
@@ -3879,19 +3902,16 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
        if (sctp_list_single_entry(&bp->address_list)) {
                addr = list_entry(bp->address_list.next,
                                  struct sctp_sockaddr_entry, list);
-               if (sctp_is_any(&addr->a_h)) {
-                       sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
-                       list_for_each(pos, &sctp_local_addr_list) {
+               if (sctp_is_any(&addr->a)) {
+                       list_for_each_safe(pos, temp, &sctp_local_addr_list) {
                                addr = list_entry(pos,
                                                  struct sctp_sockaddr_entry,
                                                  list);
                                if ((PF_INET == sk->sk_family) && 
-                                   (AF_INET6 == addr->a_h.sa.sa_family))
+                                   (AF_INET6 == addr->a.sa.sa_family))
                                        continue;
                                cnt++;
                        }
-                       sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
-                                                   flags);
                } else {
                        cnt = 1;
                }
@@ -3913,34 +3933,28 @@ 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_h.sa.sa_family))
+                   (AF_INET6 == addr->a.sa.sa_family))
                        continue;
-               memcpy(&temp, &addr->a_h, sizeof(temp));
+               memcpy(&temp, &addr->a, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
                                                                &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
-               temp.v4.sin_port = htons(port);
-               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;
 }
@@ -3948,36 +3962,30 @@ 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_h.sa.sa_family))
+                   (AF_INET6 == addr->a.sa.sa_family))
                        continue;
-               memcpy(&temp, &addr->a_h, sizeof(temp));
+               memcpy(&temp, &addr->a, sizeof(temp));
                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(space_left<addrlen)
                        return -ENOMEM;
-               temp.v4.sin_port = htons(port);
-               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;
 }
@@ -4035,7 +4043,7 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
        if (sctp_list_single_entry(&bp->address_list)) {
                addr = list_entry(bp->address_list.next,
                                  struct sctp_sockaddr_entry, list);
-               if (sctp_is_any(&addr->a_h)) {
+               if (sctp_is_any(&addr->a)) {
                        cnt = sctp_copy_laddrs_to_user_old(sk, bp->port,
                                                           getaddrs.addr_num,
                                                           to);
@@ -4049,10 +4057,9 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
 
        list_for_each(pos, &bp->address_list) {
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
-               memcpy(&temp, &addr->a_h, sizeof(temp));
+               memcpy(&temp, &addr->a, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
-               temp.v4.sin_port = htons(temp.v4.sin_port);
                if (copy_to_user(to, &temp, addrlen)) {
                        err = -EFAULT;
                        goto unlock;
@@ -4125,7 +4132,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
        if (sctp_list_single_entry(&bp->address_list)) {
                addr = list_entry(bp->address_list.next,
                                  struct sctp_sockaddr_entry, list);
-               if (sctp_is_any(&addr->a_h)) {
+               if (sctp_is_any(&addr->a)) {
                        cnt = sctp_copy_laddrs_to_user(sk, bp->port,
                                                       &to, space_left);
                        if (cnt < 0) {
@@ -4138,12 +4145,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
 
        list_for_each(pos, &bp->address_list) {
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
-               memcpy(&temp, &addr->a_h, sizeof(temp));
+               memcpy(&temp, &addr->a, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
                if(space_left < addrlen)
                        return -ENOMEM; /*fixme: right error?*/
-               temp.v4.sin_port = htons(temp.v4.sin_port);
                if (copy_to_user(to, &temp, addrlen)) {
                        err = -EFAULT;
                        goto unlock;
@@ -4191,8 +4197,8 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
        if (!asoc->peer.primary_path)
                return -ENOTCONN;
        
-       flip_to_n((union sctp_addr *)&prim.ssp_addr,
-                 &asoc->peer.primary_path->ipaddr_h);
+       memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr,
+               asoc->peer.primary_path->af_specific->sockaddr_len);
 
        sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp,
                        (union sctp_addr *)&prim.ssp_addr);
@@ -4204,21 +4210,21 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
 }
 
 /*
- * 7.1.11  Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER)
+ * 7.1.11  Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER)
  *
- * Requests that the local endpoint set the specified Adaption Layer
+ * Requests that the local endpoint set the specified Adaptation Layer
  * Indication parameter for all future INIT and INIT-ACK exchanges.
  */
-static int sctp_getsockopt_adaption_layer(struct sock *sk, int len,
+static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
                                  char __user *optval, int __user *optlen)
 {
-       struct sctp_setadaption adaption;
+       struct sctp_setadaptation adaptation;
 
-       if (len != sizeof(struct sctp_setadaption))
+       if (len != sizeof(struct sctp_setadaptation))
                return -EINVAL;
 
-       adaption.ssb_adaption_ind = sctp_sk(sk)->adaption_ind;
-       if (copy_to_user(optval, &adaption, len))
+       adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind;
+       if (copy_to_user(optval, &adaptation, len))
                return -EFAULT;
 
        return 0;
@@ -4459,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)
  *
@@ -4593,10 +4635,13 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_peer_addr_info(sk, len, optval,
                                                        optlen);
                break;
-       case SCTP_ADAPTION_LAYER:
-               retval = sctp_getsockopt_adaption_layer(sk, len, optval,
+       case SCTP_ADAPTATION_LAYER:
+               retval = sctp_getsockopt_adaptation_layer(sk, len, optval,
                                                        optlen);
                break;
+       case SCTP_CONTEXT:
+               retval = sctp_getsockopt_context(sk, len, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -4635,11 +4680,9 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 {
        struct sctp_bind_hashbucket *head; /* hash list */
        struct sctp_bind_bucket *pp; /* hash list port iterator */
-       union sctp_addr tmp;
        unsigned short snum;
        int ret;
 
-       flip_to_h(&tmp, addr);
        snum = ntohs(addr->v4.sin_port);
 
        SCTP_DEBUG_PRINTK("sctp_get_port() begins, snum=%d\n", snum);
@@ -4737,7 +4780,7 @@ pp_found:
                        if (reuse && sk2->sk_reuse)
                                continue;
 
-                       if (sctp_bind_addr_match(&ep2->base.bind_addr, &tmp,
+                       if (sctp_bind_addr_match(&ep2->base.bind_addr, addr,
                                                 sctp_sk(sk))) {
                                ret = (long)sk2;
                                goto fail_unlock;
@@ -5016,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;
@@ -5075,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;