Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / net / sctp / socket.c
index 5219c3b..dab1594 100644 (file)
  * be incorporated into the next SCTP release.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/wait.h>
 #include <linux/time.h>
 #include <linux/ip.h>
+#include <linux/capability.h>
 #include <linux/fcntl.h>
 #include <linux/poll.h>
 #include <linux/init.h>
@@ -86,8 +86,6 @@
 
 /* Forward declarations for internal helper functions. */
 static int sctp_writeable(struct sock *sk);
-static inline int sctp_wspace(struct sctp_association *asoc);
-static inline void sctp_set_owner_w(struct sctp_chunk *chunk);
 static void sctp_wfree(struct sk_buff *skb);
 static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,
                                size_t msg_len);
@@ -95,7 +93,8 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p);
 static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
 static int sctp_wait_for_accept(struct sock *sk, long timeo);
 static void sctp_wait_for_close(struct sock *sk, long timeo);
-static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int);
+static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
+                                       union sctp_addr *addr, int len);
 static int sctp_bindx_add(struct sock *, struct sockaddr *, int);
 static int sctp_bindx_rem(struct sock *, struct sockaddr *, int);
 static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int);
@@ -109,7 +108,77 @@ static void sctp_sock_migrate(struct sock *, struct sock *,
 static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;
 
 extern kmem_cache_t *sctp_bucket_cachep;
-extern int sctp_assoc_valid(struct sock *sk, struct sctp_association *asoc);
+
+/* Get the sndbuf space available at the time on the association.  */
+static inline int sctp_wspace(struct sctp_association *asoc)
+{
+       struct sock *sk = asoc->base.sk;
+       int amt = 0;
+
+       if (asoc->ep->sndbuf_policy) {
+               /* make sure that no association uses more than sk_sndbuf */
+               amt = sk->sk_sndbuf - asoc->sndbuf_used;
+       } else {
+               /* do socket level accounting */
+               amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+       }
+
+       if (amt < 0)
+               amt = 0;
+
+       return amt;
+}
+
+/* Increment the used sndbuf space count of the corresponding association by
+ * the size of the outgoing data chunk.
+ * Also, set the skb destructor for sndbuf accounting later.
+ *
+ * Since it is always 1-1 between chunk and skb, and also a new skb is always
+ * allocated for chunk bundling in sctp_packet_transmit(), we can use the
+ * destructor in the data chunk skb for the purpose of the sndbuf space
+ * tracking.
+ */
+static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
+{
+       struct sctp_association *asoc = chunk->asoc;
+       struct sock *sk = asoc->base.sk;
+
+       /* The sndbuf space is tracked per association.  */
+       sctp_association_hold(asoc);
+
+       skb_set_owner_w(chunk->skb, sk);
+
+       chunk->skb->destructor = sctp_wfree;
+       /* Save the chunk pointer in skb for sctp_wfree to use later.  */
+       *((struct sctp_chunk **)(chunk->skb->cb)) = chunk;
+
+       asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) +
+                               sizeof(struct sk_buff) +
+                               sizeof(struct sctp_chunk);
+
+       atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
+}
+
+/* Verify that this is a valid address. */
+static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
+                                  int len)
+{
+       struct sctp_af *af;
+
+       /* Verify basic sockaddr. */
+       af = sctp_sockaddr_af(sctp_sk(sk), addr, len);
+       if (!af)
+               return -EINVAL;
+
+       /* Is this a valid SCTP address?  */
+       if (!af->addr_valid(addr, sctp_sk(sk), NULL))
+               return -EINVAL;
+
+       if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr)))
+               return -EINVAL;
+
+       return 0;
+}
 
 /* Look up the association by its id.  If this is not a UDP-style
  * socket, the ID field is always ignored.
@@ -152,7 +221,7 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
  * id are specified, the associations matching the address and the id should be
  * the same.
  */
-struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
+static struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
                                              struct sockaddr_storage *addr,
                                              sctp_assoc_t id)
 {
@@ -189,18 +258,18 @@ struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
  *             sockaddr_in6 [RFC 2553]),
  *   addr_len - the size of the address structure.
  */
-int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+SCTP_STATIC int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len)
 {
        int retval = 0;
 
        sctp_lock_sock(sk);
 
-       SCTP_DEBUG_PRINTK("sctp_bind(sk: %p, uaddr: %p, addr_len: %d)\n",
-                         sk, uaddr, addr_len);
+       SCTP_DEBUG_PRINTK("sctp_bind(sk: %p, addr: %p, addr_len: %d)\n",
+                         sk, addr, addr_len);
 
        /* Disallow binding twice. */
        if (!sctp_sk(sk)->ep->base.bind_addr.port)
-               retval = sctp_do_bind(sk, (union sctp_addr *)uaddr,
+               retval = sctp_do_bind(sk, (union sctp_addr *)addr,
                                      addr_len);
        else
                retval = -EINVAL;
@@ -213,7 +282,7 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 static long sctp_get_port_local(struct sock *, union sctp_addr *);
 
 /* Verify this is a valid sockaddr. */
-static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt,
+static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
                                        union sctp_addr *addr, int len)
 {
        struct sctp_af *af;
@@ -238,30 +307,34 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt,
 /* Bind a local address either to an endpoint or to an association.  */
 SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
 {
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
        struct sctp_endpoint *ep = sp->ep;
        struct sctp_bind_addr *bp = &ep->base.bind_addr;
        struct sctp_af *af;
        unsigned short snum;
        int ret = 0;
 
-       SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, len: %d)\n",
-                         sk, addr, len);
-
        /* Common sockaddr verification. */
        af = sctp_sockaddr_af(sp, addr, len);
-       if (!af)
+       if (!af) {
+               SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, len: %d) EINVAL\n",
+                                 sk, addr, len);
                return -EINVAL;
+       }
+
+       snum = ntohs(addr->v4.sin_port);
+
+       SCTP_DEBUG_PRINTK_IPADDR("sctp_do_bind(sk: %p, new addr: ",
+                                ", port: %d, new port: %d, len: %d)\n",
+                                sk,
+                                addr,
+                                bp->port, snum,
+                                len);
 
        /* PF specific bind() address verification. */
        if (!sp->pf->bind_verify(sp, addr))
                return -EADDRNOTAVAIL;
 
-       snum= ntohs(addr->v4.sin_port);
-
-       SCTP_DEBUG_PRINTK("sctp_do_bind: port: %d, new port: %d\n",
-                         bp->port, snum);
-
        /* We must either be unbound, or bind to the same port.  */
        if (bp->port && (snum != bp->port)) {
                SCTP_DEBUG_PRINTK("sctp_do_bind:"
@@ -287,8 +360,8 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
        }
 
        /* Refresh ephemeral port.  */
-       if (!snum)
-               snum = inet_sk(sk)->num;
+       if (!bp->port)
+               bp->port = inet_sk(sk)->num;
 
        /* Add the address to the bind address list.  */
        sctp_local_bh_disable();
@@ -296,10 +369,8 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
 
        /* Use GFP_ATOMIC since BHs are disabled.  */
        addr->v4.sin_port = ntohs(addr->v4.sin_port);
-       ret = sctp_add_bind_addr(bp, addr, GFP_ATOMIC);
+       ret = sctp_add_bind_addr(bp, addr, 1, GFP_ATOMIC);
        addr->v4.sin_port = htons(addr->v4.sin_port);
-       if (!ret && !bp->port)
-               bp->port = snum;
        sctp_write_unlock(&ep->base.addr_lock);
        sctp_local_bh_enable();
 
@@ -331,7 +402,7 @@ static int sctp_send_asconf(struct sctp_association *asoc,
         * transmission.
         */     
        if (asoc->addip_last_asconf) {
-               __skb_queue_tail(&asoc->addip_chunks, (struct sk_buff *)chunk);
+               list_add_tail(&chunk->list, &asoc->addip_chunk_list);
                goto out;       
        }
 
@@ -413,13 +484,14 @@ static int sctp_send_asconf_add_ip(struct sock            *sk,
                                   struct sockaddr      *addrs,
                                   int                  addrcnt)
 {
-       struct sctp_opt                 *sp;
+       struct sctp_sock                *sp;
        struct sctp_endpoint            *ep;
        struct sctp_association         *asoc;
        struct sctp_bind_addr           *bp;
        struct sctp_chunk               *chunk;
        struct sctp_sockaddr_entry      *laddr;
        union sctp_addr                 *addr;
+       union sctp_addr                 saveaddr;
        void                            *addr_buf;
        struct sctp_af                  *af;
        struct list_head                *pos;
@@ -487,14 +559,26 @@ static int sctp_send_asconf_add_ip(struct sock            *sk,
                }
 
                retval = sctp_send_asconf(asoc, chunk);
+               if (retval)
+                       goto out;
 
-               /* FIXME: After sending the add address ASCONF chunk, we
-                * cannot append the address to the association's binding
-                * address list, because the new address may be used as the
-                * source of a message sent to the peer before the ASCONF
-                * chunk is received by the peer.  So we should wait until
-                * ASCONF_ACK is received.
+               /* Add the new addresses to the bind address list with
+                * use_as_src set to 0.
                 */
+               sctp_local_bh_disable();
+               sctp_write_lock(&asoc->base.addr_lock);
+               addr_buf = addrs;
+               for (i = 0; i < addrcnt; i++) {
+                       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;
+               }
+               sctp_write_unlock(&asoc->base.addr_lock);
+               sctp_local_bh_enable();
        }
 
 out:
@@ -518,7 +602,7 @@ out:
  */
 int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
 {
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
        struct sctp_endpoint *ep = sp->ep;
        int cnt;
        struct sctp_bind_addr *bp = &ep->base.bind_addr;
@@ -602,15 +686,18 @@ static int sctp_send_asconf_del_ip(struct sock            *sk,
                                   struct sockaddr      *addrs,
                                   int                  addrcnt)
 {
-       struct sctp_opt         *sp;
+       struct sctp_sock        *sp;
        struct sctp_endpoint    *ep;
        struct sctp_association *asoc;
+       struct sctp_transport   *transport;
        struct sctp_bind_addr   *bp;
        struct sctp_chunk       *chunk;
        union sctp_addr         *laddr;
+       union sctp_addr         saveaddr;
        void                    *addr_buf;
        struct sctp_af          *af;
-       struct list_head        *pos;
+       struct list_head        *pos, *pos1;
+       struct sctp_sockaddr_entry *saddr;
        int                     i;
        int                     retval = 0;
 
@@ -677,14 +764,42 @@ static int sctp_send_asconf_del_ip(struct sock            *sk,
                        goto out;
                }
 
-               retval = sctp_send_asconf(asoc, chunk);
+               /* Reset use_as_src flag for the addresses in the bind address
+                * list that are to be deleted.
+                */
+               sctp_local_bh_disable();
+               sctp_write_lock(&asoc->base.addr_lock);
+               addr_buf = addrs;
+               for (i = 0; i < addrcnt; i++) {
+                       laddr = (union sctp_addr *)addr_buf;
+                       af = sctp_get_af_specific(laddr->v4.sin_family);
+                       memcpy(&saveaddr, laddr, af->sockaddr_len);
+                       saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port);
+                       list_for_each(pos1, &bp->address_list) {
+                               saddr = list_entry(pos1,
+                                                  struct sctp_sockaddr_entry,
+                                                  list);
+                               if (sctp_cmp_addr_exact(&saddr->a, &saveaddr))
+                                       saddr->use_as_src = 0;
+                       }
+                       addr_buf += af->sockaddr_len;
+               }
+               sctp_write_unlock(&asoc->base.addr_lock);
+               sctp_local_bh_enable();
 
-               /* FIXME: After sending the delete address ASCONF chunk, we
-                * cannot remove the addresses from the association's bind
-                * address list, because there maybe some packet send to
-                * the delete addresses, so we should wait until ASCONF_ACK
-                * packet is received.
+               /* Update the route and saddr entries for all the transports
+                * as some of the addresses in the bind address list are
+                * about to be deleted and cannot be used as source addresses.
                 */
+               list_for_each(pos1, &asoc->peer.transport_addr_list) {
+                       transport = list_entry(pos1, struct sctp_transport,
+                                              transports);
+                       dst_release(transport->dst);
+                       sctp_transport_route(transport, NULL,
+                                            sctp_sk(asoc->base.sk));
+               }
+
+               retval = sctp_send_asconf(asoc, chunk);
        }
 out:
        return retval;
@@ -745,7 +860,8 @@ out:
  *
  * Basically do nothing but copying the addresses from user to kernel
  * land and invoking either sctp_bindx_add() or sctp_bindx_rem() on the sk.
- * This is used for tunneling the sctp_bindx() request through sctp_setsockopt() * from userspace.
+ * This is used for tunneling the sctp_bindx() request through sctp_setsockopt()
+ * from userspace.
  *
  * We don't use copy_from_user() for optimization: we first do the
  * sanity checks (buffer size -fast- and access check-healthy
@@ -765,7 +881,8 @@ out:
  *
  * Returns 0 if ok, <0 errno code on error.
  */
-SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr *addrs,
+SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,
+                                     struct sockaddr __user *addrs,
                                      int addrs_size, int op)
 {
        struct sockaddr *kaddrs;
@@ -787,7 +904,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr *addrs,
                return -EFAULT;
 
        /* Alloc space for the address array in kernel memory.  */
-       kaddrs = (struct sockaddr *)kmalloc(addrs_size, GFP_KERNEL);
+       kaddrs = kmalloc(addrs_size, GFP_KERNEL);
        if (unlikely(!kaddrs))
                return -ENOMEM;
 
@@ -841,6 +958,257 @@ out:
        return err;
 }
 
+/* __sctp_connect(struct sock* sk, struct sockaddr *kaddrs, int addrs_size)
+ *
+ * Common routine for handling connect() and sctp_connectx().
+ * Connect will come in with just a single address.
+ */
+static int __sctp_connect(struct sock* sk,
+                         struct sockaddr *kaddrs,
+                         int addrs_size)
+{
+       struct sctp_sock *sp;
+       struct sctp_endpoint *ep;
+       struct sctp_association *asoc = NULL;
+       struct sctp_association *asoc2;
+       struct sctp_transport *transport;
+       union sctp_addr to;
+       struct sctp_af *af;
+       sctp_scope_t scope;
+       long timeo;
+       int err = 0;
+       int addrcnt = 0;
+       int walk_size = 0;
+       struct sockaddr *sa_addr;
+       void *addr_buf;
+
+       sp = sctp_sk(sk);
+       ep = sp->ep;
+
+       /* connect() cannot be done on a socket that is already in ESTABLISHED
+        * state - UDP-style peeled off socket or a TCP-style socket that
+        * is already connected.
+        * It cannot be done even on a TCP-style listening socket.
+        */
+       if (sctp_sstate(sk, ESTABLISHED) ||
+           (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) {
+               err = -EISCONN;
+               goto out_free;
+       }
+
+       /* 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);
+
+               /* If the address family is not supported or if this address
+                * causes the address buffer to overflow return EINVAL.
+                */
+               if (!af || (walk_size + af->sockaddr_len) > addrs_size) {
+                       err = -EINVAL;
+                       goto out_free;
+               }
+
+               err = sctp_verify_addr(sk, (union sctp_addr *)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);
+               if (asoc2 && asoc2 != asoc) {
+                       if (asoc2->state >= SCTP_STATE_ESTABLISHED)
+                               err = -EISCONN;
+                       else
+                               err = -EALREADY;
+                       goto out_free;
+               }
+
+               /* If we could not find a matching association on the endpoint,
+                * 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)) {
+                       err = -EADDRNOTAVAIL;
+                       goto out_free;
+               }
+
+               if (!asoc) {
+                       /* If a bind() or sctp_bindx() is not called prior to
+                        * an sctp_connectx() call, the system picks an
+                        * ephemeral port and will choose an address set
+                        * equivalent to binding with a wildcard address.
+                        */
+                       if (!ep->base.bind_addr.port) {
+                               if (sctp_autobind(sk)) {
+                                       err = -EAGAIN;
+                                       goto out_free;
+                               }
+                       } else {
+                               /*
+                                * If an unprivileged user inherits a 1-many 
+                                * style socket with open associations on a 
+                                * privileged port, it MAY be permitted to 
+                                * accept new associations, but it SHOULD NOT 
+                                * be permitted to open new associations.
+                                */
+                               if (ep->base.bind_addr.port < PROT_SOCK &&
+                                   !capable(CAP_NET_BIND_SERVICE)) {
+                                       err = -EACCES;
+                                       goto out_free;
+                               }
+                       }
+
+                       scope = sctp_scope(&to);
+                       asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);
+                       if (!asoc) {
+                               err = -ENOMEM;
+                               goto out_free;
+                       }
+               }
+
+               /* Prime the peer's transport structures.  */
+               transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL,
+                                               SCTP_UNKNOWN);
+               if (!transport) {
+                       err = -ENOMEM;
+                       goto out_free;
+               }
+
+               addrcnt++;
+               addr_buf += af->sockaddr_len;
+               walk_size += af->sockaddr_len;
+       }
+
+       err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL);
+       if (err < 0) {
+               goto out_free;
+       }
+
+       err = sctp_primitive_ASSOCIATE(asoc, NULL);
+       if (err < 0) {
+               goto out_free;
+       }
+
+       /* Initialize sk's dport and daddr for getpeername() */
+       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);
+
+       /* Don't free association on exit. */
+       asoc = NULL;
+
+out_free:
+
+       SCTP_DEBUG_PRINTK("About to exit __sctp_connect() free asoc: %p"
+                         " kaddrs: %p err: %d\n",
+                         asoc, kaddrs, err);
+       if (asoc)
+               sctp_association_free(asoc);
+       return err;
+}
+
+/* Helper for tunneling sctp_connectx() requests through sctp_setsockopt()
+ *
+ * API 8.9
+ * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt);
+ *
+ * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses.
+ * If the sd is an IPv6 socket, the addresses passed can either be IPv4
+ * or IPv6 addresses.
+ *
+ * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see
+ * Section 3.1.2 for this usage.
+ *
+ * addrs is a pointer to an array of one or more socket addresses. Each
+ * address is contained in its appropriate structure (i.e. struct
+ * sockaddr_in or struct sockaddr_in6) the family of the address type
+ * must be used to distengish the address length (note that this
+ * representation is termed a "packed array" of addresses). The caller
+ * specifies the number of addresses in the array with addrcnt.
+ *
+ * On success, sctp_connectx() returns 0. On failure, sctp_connectx() returns
+ * -1, and sets errno to the appropriate error code.
+ *
+ * For SCTP, the port given in each socket address must be the same, or
+ * sctp_connectx() will fail, setting errno to EINVAL.
+ *
+ * An application can use sctp_connectx to initiate an association with
+ * an endpoint that is multi-homed.  Much like sctp_bindx() this call
+ * allows a caller to specify multiple addresses at which a peer can be
+ * reached.  The way the SCTP stack uses the list of addresses to set up
+ * the association is implementation dependant.  This function only
+ * specifies that the stack will try to make use of all the addresses in
+ * the list when needed.
+ *
+ * Note that the list of addresses passed in is only used for setting up
+ * the association.  It does not necessarily equal the set of addresses
+ * the peer uses for the resulting association.  If the caller wants to
+ * find out the set of peer addresses, it must use sctp_getpaddrs() to
+ * retrieve them after the association has been set up.
+ *
+ * Basically do nothing but copying the addresses from user to kernel
+ * land and invoking either sctp_connectx(). This is used for tunneling
+ * the sctp_connectx() request through sctp_setsockopt() from userspace.
+ *
+ * We don't use copy_from_user() for optimization: we first do the
+ * sanity checks (buffer size -fast- and access check-healthy
+ * pointer); if all of those succeed, then we can alloc the memory
+ * (expensive operation) needed to copy the data to kernel. Then we do
+ * the copying without checking the user space area
+ * (__copy_from_user()).
+ *
+ * On exit there is no need to do sockfd_put(), sys_setsockopt() does
+ * it.
+ *
+ * sk        The sk of the socket
+ * addrs     The pointer to the addresses in user land
+ * addrssize Size of the addrs buffer
+ *
+ * Returns 0 if ok, <0 errno code on error.
+ */
+SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
+                                     struct sockaddr __user *addrs,
+                                     int addrs_size)
+{
+       int err = 0;
+       struct sockaddr *kaddrs;
+
+       SCTP_DEBUG_PRINTK("%s - sk %p addrs %p addrs_size %d\n",
+                         __FUNCTION__, sk, addrs, addrs_size);
+
+       if (unlikely(addrs_size <= 0))
+               return -EINVAL;
+
+       /* Check the user passed a healthy pointer.  */
+       if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size)))
+               return -EFAULT;
+
+       /* Alloc space for the address array in kernel memory.  */
+       kaddrs = kmalloc(addrs_size, GFP_KERNEL);
+       if (unlikely(!kaddrs))
+               return -ENOMEM;
+
+       if (__copy_from_user(kaddrs, addrs, addrs_size)) {
+               err = -EFAULT;
+       } else {
+               err = __sctp_connect(sk, kaddrs, addrs_size);
+       }
+
+       kfree(kaddrs);
+       return err;
+}
+
 /* API 3.1.4 close() - UDP Style Syntax
  * Applications use close() to perform graceful shutdown (as described in
  * Section 10.1 of [SCTP]) on ALL the associations currently represented
@@ -904,7 +1272,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);
 
@@ -917,12 +1285,16 @@ 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);
+               if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
+                       struct sctp_chunk *chunk;
+
+                       chunk = sctp_make_abort_user(asoc, NULL, 0);
+                       if (chunk)
+                               sctp_primitive_ABORT(asoc, chunk);
                } else
                        sctp_primitive_SHUTDOWN(asoc, NULL);
        }
@@ -944,11 +1316,11 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
        sctp_local_bh_disable();
        sctp_bh_lock_sock(sk);
 
-       /* Hold the sock, since inet_sock_release() will put sock_put()
+       /* Hold the sock, since sk_common_release() will put sock_put()
         * and we have just a little more cleanup.
         */
        sock_hold(sk);
-       inet_sock_release(sk);
+       sk_common_release(sk);
 
        sctp_bh_unlock_sock(sk);
        sctp_local_bh_enable();
@@ -989,14 +1361,14 @@ static int sctp_error(struct sock *sk, int flags, int err)
  * Note:  This function could use a rewrite especially when explicit
  * connect support comes in.
  */
-/* BUG:  We do not implement the equivalent of wait_for_tcp_memory(). */
+/* BUG:  We do not implement the equivalent of sk_stream_wait_memory(). */
 
 SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *);
 
 SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                             struct msghdr *msg, size_t msg_len)
 {
-       struct sctp_opt *sp;
+       struct sctp_sock *sp;
        struct sctp_endpoint *ep;
        struct sctp_association *new_asoc=NULL, *asoc=NULL;
        struct sctp_transport *transport, *chunk_tp;
@@ -1006,8 +1378,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        struct sctp_sndrcvinfo default_sinfo = { 0 };
        struct sctp_sndrcvinfo *sinfo;
        struct sctp_initmsg *sinit;
-       sctp_assoc_t associd = NULL;
-       sctp_cmsgs_t cmsgs = { 0 };
+       sctp_assoc_t associd = 0;
+       sctp_cmsgs_t cmsgs = { NULL };
        int err;
        sctp_scope_t scope;
        long timeo;
@@ -1023,7 +1395,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        sp = sctp_sk(sk);
        ep = sp->ep;
 
-       SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name);
+       SCTP_DEBUG_PRINTK("Using endpoint: %p.\n", ep);
 
        /* We cannot send a message over a TCP-style listening socket. */
        if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) {
@@ -1075,27 +1447,27 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        SCTP_DEBUG_PRINTK("msg_len: %zu, sinfo_flags: 0x%x\n",
                          msg_len, sinfo_flags);
 
-       /* MSG_EOF or MSG_ABORT cannot be set on a TCP-style socket. */
-       if (sctp_style(sk, TCP) && (sinfo_flags & (MSG_EOF | MSG_ABORT))) {
+       /* SCTP_EOF or SCTP_ABORT cannot be set on a TCP-style socket. */
+       if (sctp_style(sk, TCP) && (sinfo_flags & (SCTP_EOF | SCTP_ABORT))) {
                err = -EINVAL;
                goto out_nounlock;
        }
 
-       /* If MSG_EOF is set, no data can be sent. Disallow sending zero
-        * length messages when MSG_EOF|MSG_ABORT is not set.
-        * If MSG_ABORT is set, the message length could be non zero with
+       /* If SCTP_EOF is set, no data can be sent. Disallow sending zero
+        * length messages when SCTP_EOF|SCTP_ABORT is not set.
+        * If SCTP_ABORT is set, the message length could be non zero with
         * the msg_iov set to the user abort reason.
         */
-       if (((sinfo_flags & MSG_EOF) && (msg_len > 0)) ||
-           (!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) {
+       if (((sinfo_flags & SCTP_EOF) && (msg_len > 0)) ||
+           (!(sinfo_flags & (SCTP_EOF|SCTP_ABORT)) && (msg_len == 0))) {
                err = -EINVAL;
                goto out_nounlock;
        }
 
-       /* If MSG_ADDR_OVER is set, there must be an address
+       /* If SCTP_ADDR_OVER is set, there must be an address
         * specified in msg_name.
         */
-       if ((sinfo_flags & MSG_ADDR_OVER) && (!msg->msg_name)) {
+       if ((sinfo_flags & SCTP_ADDR_OVER) && (!msg->msg_name)) {
                err = -EINVAL;
                goto out_nounlock;
        }
@@ -1144,16 +1516,24 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                        goto out_unlock;
                }
 
-               if (sinfo_flags & MSG_EOF) {
+               if (sinfo_flags & SCTP_EOF) {
                        SCTP_DEBUG_PRINTK("Shutting down association: %p\n",
                                          asoc);
                        sctp_primitive_SHUTDOWN(asoc, NULL);
                        err = 0;
                        goto out_unlock;
                }
-               if (sinfo_flags & MSG_ABORT) {
+               if (sinfo_flags & SCTP_ABORT) {
+                       struct sctp_chunk *chunk;
+
+                       chunk = sctp_make_abort_user(asoc, msg, msg_len);
+                       if (!chunk) {
+                               err = -ENOMEM;
+                               goto out_unlock;
+                       }
+
                        SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc);
-                       sctp_primitive_ABORT(asoc, msg);
+                       sctp_primitive_ABORT(asoc, chunk);
                        err = 0;
                        goto out_unlock;
                }
@@ -1163,6 +1543,11 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        if (!asoc) {
                SCTP_DEBUG_PRINTK("There is no association yet.\n");
 
+               if (sinfo_flags & (SCTP_EOF | SCTP_ABORT)) {
+                       err = -EINVAL;
+                       goto out_unlock;
+               }
+
                /* Check for invalid stream against the stream counts,
                 * either the default or the user specified stream counts.
                 */
@@ -1196,6 +1581,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                                err = -EAGAIN;
                                goto out_unlock;
                        }
+               } else {
+                       /*
+                        * If an unprivileged user inherits a one-to-many
+                        * style socket with open associations on a privileged
+                        * port, it MAY be permitted to accept new associations,
+                        * but it SHOULD NOT be permitted to open new
+                        * associations.
+                        */
+                       if (ep->base.bind_addr.port < PROT_SOCK &&
+                           !capable(CAP_NET_BIND_SERVICE)) {
+                               err = -EACCES;
+                               goto out_unlock;
+                       }
                }
 
                scope = sctp_scope(&to);
@@ -1224,12 +1622,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                        }
                        if (sinit->sinit_max_init_timeo) {
                                asoc->max_init_timeo = 
-                                MSECS_TO_JIFFIES(sinit->sinit_max_init_timeo);
+                                msecs_to_jiffies(sinit->sinit_max_init_timeo);
                        }
                }
 
                /* Prime the peer's transport structures.  */
-               transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL);
+               transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL, SCTP_UNKNOWN);
                if (!transport) {
                        err = -ENOMEM;
                        goto out_free;
@@ -1292,10 +1690,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
 
        /* If an address is passed with the sendto/sendmsg call, it is used
         * to override the primary destination address in the TCP model, or
-        * when MSG_ADDR_OVER flag is set in the UDP model.
+        * when SCTP_ADDR_OVER flag is set in the UDP model.
         */
        if ((sctp_style(sk, TCP) && msg_name) ||
-           (sinfo_flags & MSG_ADDR_OVER)) {
+           (sinfo_flags & SCTP_ADDR_OVER)) {
                chunk_tp = sctp_assoc_lookup_paddr(asoc, &to);
                if (!chunk_tp) {
                        err = -EINVAL;
@@ -1432,7 +1830,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
                             int flags, int *addr_len)
 {
        struct sctp_ulpevent *event = NULL;
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
        struct sk_buff *skb;
        int copied;
        int err = 0;
@@ -1538,14 +1936,14 @@ out:
  * instead a error will be indicated to the user.
  */
 static int sctp_setsockopt_disable_fragments(struct sock *sk,
-                                                   char *optval, int optlen)
+                                           char __user *optval, int optlen)
 {
        int val;
 
        if (optlen < sizeof(int))
                return -EINVAL;
 
-       if (get_user(val, (int *)optval))
+       if (get_user(val, (int __user *)optval))
                return -EFAULT;
 
        sctp_sk(sk)->disable_fragments = (val == 0) ? 0 : 1;
@@ -1553,7 +1951,7 @@ static int sctp_setsockopt_disable_fragments(struct sock *sk,
        return 0;
 }
 
-static int sctp_setsockopt_events(struct sock *sk, char *optval,
+static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
                                        int optlen)
 {
        if (optlen != sizeof(struct sctp_event_subscribe))
@@ -1574,10 +1972,10 @@ static int sctp_setsockopt_events(struct sock *sk, char *optval,
  * integer defining the number of seconds of idle time before an
  * association is closed.
  */
-static int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
+static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
                                            int optlen)
 {
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
 
        /* Applicable to UDP-style socket only */
        if (sctp_style(sk, TCP))
@@ -1587,7 +1985,6 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
        if (copy_from_user(&sp->autoclose, optval, optlen))
                return -EFAULT;
 
-       sp->ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ;
        return 0;
 }
 
@@ -1601,80 +1998,382 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
  * address's parameters:
  *
  *  struct sctp_paddrparams {
- *      sctp_assoc_t            spp_assoc_id;
- *      struct sockaddr_storage spp_address;
- *      uint32_t                spp_hbinterval;
- *      uint16_t                spp_pathmaxrxt;
- *  };
- *
- *   spp_assoc_id    - (UDP style socket) This is filled in the application,
- *                     and identifies the association for this query.
+ *     sctp_assoc_t            spp_assoc_id;
+ *     struct sockaddr_storage spp_address;
+ *     uint32_t                spp_hbinterval;
+ *     uint16_t                spp_pathmaxrxt;
+ *     uint32_t                spp_pathmtu;
+ *     uint32_t                spp_sackdelay;
+ *     uint32_t                spp_flags;
+ * };
+ *
+ *   spp_assoc_id    - (one-to-many style socket) This is filled in the
+ *                     application, and identifies the association for
+ *                     this query.
  *   spp_address     - This specifies which address is of interest.
  *   spp_hbinterval  - This contains the value of the heartbeat interval,
- *                     in milliseconds.  A value of 0, when modifying the
- *                     parameter, specifies that the heartbeat on this
- *                     address should be disabled. A value of UINT32_MAX
- *                     (4294967295), when modifying the parameter,
- *                     specifies that a heartbeat should be sent
- *                     immediately to the peer address, and the current
- *                     interval should remain unchanged.
+ *                     in milliseconds.  If a  value of zero
+ *                     is present in this field then no changes are to
+ *                     be made to this parameter.
  *   spp_pathmaxrxt  - This contains the maximum number of
  *                     retransmissions before this address shall be
- *                     considered unreachable.
+ *                     considered unreachable. If a  value of zero
+ *                     is present in this field then no changes are to
+ *                     be made to this parameter.
+ *   spp_pathmtu     - When Path MTU discovery is disabled the value
+ *                     specified here will be the "fixed" path mtu.
+ *                     Note that if the spp_address field is empty
+ *                     then all associations on this address will
+ *                     have this fixed path mtu set upon them.
+ *
+ *   spp_sackdelay   - When delayed sack is enabled, this value specifies
+ *                     the number of milliseconds that sacks will be delayed
+ *                     for. This value will apply to all addresses of an
+ *                     association if the spp_address field is empty. Note
+ *                     also, that if delayed sack is enabled and this
+ *                     value is set to 0, no change is made to the last
+ *                     recorded delayed sack timer value.
+ *
+ *   spp_flags       - These flags are used to control various features
+ *                     on an association. The flag field may contain
+ *                     zero or more of the following options.
+ *
+ *                     SPP_HB_ENABLE  - Enable heartbeats on the
+ *                     specified address. Note that if the address
+ *                     field is empty all addresses for the association
+ *                     have heartbeats enabled upon them.
+ *
+ *                     SPP_HB_DISABLE - Disable heartbeats on the
+ *                     speicifed address. Note that if the address
+ *                     field is empty all addresses for the association
+ *                     will have their heartbeats disabled. Note also
+ *                     that SPP_HB_ENABLE and SPP_HB_DISABLE are
+ *                     mutually exclusive, only one of these two should
+ *                     be specified. Enabling both fields will have
+ *                     undetermined results.
+ *
+ *                     SPP_HB_DEMAND - Request a user initiated heartbeat
+ *                     to be made immediately.
+ *
+ *                     SPP_PMTUD_ENABLE - This field will enable PMTU
+ *                     discovery upon the specified address. Note that
+ *                     if the address feild is empty then all addresses
+ *                     on the association are effected.
+ *
+ *                     SPP_PMTUD_DISABLE - This field will disable PMTU
+ *                     discovery upon the specified address. Note that
+ *                     if the address feild is empty then all addresses
+ *                     on the association are effected. Not also that
+ *                     SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually
+ *                     exclusive. Enabling both will have undetermined
+ *                     results.
+ *
+ *                     SPP_SACKDELAY_ENABLE - Setting this flag turns
+ *                     on delayed sack. The time specified in spp_sackdelay
+ *                     is used to specify the sack delay for this address. Note
+ *                     that if spp_address is empty then all addresses will
+ *                     enable delayed sack and take on the sack delay
+ *                     value specified in spp_sackdelay.
+ *                     SPP_SACKDELAY_DISABLE - Setting this flag turns
+ *                     off delayed sack. If the spp_address field is blank then
+ *                     delayed sack is disabled for the entire association. Note
+ *                     also that this field is mutually exclusive to
+ *                     SPP_SACKDELAY_ENABLE, setting both will have undefined
+ *                     results.
  */
+int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
+                               struct sctp_transport   *trans,
+                               struct sctp_association *asoc,
+                               struct sctp_sock        *sp,
+                               int                      hb_change,
+                               int                      pmtud_change,
+                               int                      sackdelay_change)
+{
+       int error;
+
+       if (params->spp_flags & SPP_HB_DEMAND && trans) {
+               error = sctp_primitive_REQUESTHEARTBEAT (trans->asoc, trans);
+               if (error)
+                       return error;
+       }
+
+       if (params->spp_hbinterval) {
+               if (trans) {
+                       trans->hbinterval = msecs_to_jiffies(params->spp_hbinterval);
+               } else if (asoc) {
+                       asoc->hbinterval = msecs_to_jiffies(params->spp_hbinterval);
+               } else {
+                       sp->hbinterval = params->spp_hbinterval;
+               }
+       }
+
+       if (hb_change) {
+               if (trans) {
+                       trans->param_flags =
+                               (trans->param_flags & ~SPP_HB) | hb_change;
+               } else if (asoc) {
+                       asoc->param_flags =
+                               (asoc->param_flags & ~SPP_HB) | hb_change;
+               } else {
+                       sp->param_flags =
+                               (sp->param_flags & ~SPP_HB) | hb_change;
+               }
+       }
+
+       if (params->spp_pathmtu) {
+               if (trans) {
+                       trans->pathmtu = params->spp_pathmtu;
+                       sctp_assoc_sync_pmtu(asoc);
+               } else if (asoc) {
+                       asoc->pathmtu = params->spp_pathmtu;
+                       sctp_frag_point(sp, params->spp_pathmtu);
+               } else {
+                       sp->pathmtu = params->spp_pathmtu;
+               }
+       }
+
+       if (pmtud_change) {
+               if (trans) {
+                       int update = (trans->param_flags & SPP_PMTUD_DISABLE) &&
+                               (params->spp_flags & SPP_PMTUD_ENABLE);
+                       trans->param_flags =
+                               (trans->param_flags & ~SPP_PMTUD) | pmtud_change;
+                       if (update) {
+                               sctp_transport_pmtu(trans);
+                               sctp_assoc_sync_pmtu(asoc);
+                       }
+               } else if (asoc) {
+                       asoc->param_flags =
+                               (asoc->param_flags & ~SPP_PMTUD) | pmtud_change;
+               } else {
+                       sp->param_flags =
+                               (sp->param_flags & ~SPP_PMTUD) | pmtud_change;
+               }
+       }
+
+       if (params->spp_sackdelay) {
+               if (trans) {
+                       trans->sackdelay =
+                               msecs_to_jiffies(params->spp_sackdelay);
+               } else if (asoc) {
+                       asoc->sackdelay =
+                               msecs_to_jiffies(params->spp_sackdelay);
+               } else {
+                       sp->sackdelay = params->spp_sackdelay;
+               }
+       }
+
+       if (sackdelay_change) {
+               if (trans) {
+                       trans->param_flags =
+                               (trans->param_flags & ~SPP_SACKDELAY) |
+                               sackdelay_change;
+               } else if (asoc) {
+                       asoc->param_flags =
+                               (asoc->param_flags & ~SPP_SACKDELAY) |
+                               sackdelay_change;
+               } else {
+                       sp->param_flags =
+                               (sp->param_flags & ~SPP_SACKDELAY) |
+                               sackdelay_change;
+               }
+       }
+
+       if (params->spp_pathmaxrxt) {
+               if (trans) {
+                       trans->pathmaxrxt = params->spp_pathmaxrxt;
+               } else if (asoc) {
+                       asoc->pathmaxrxt = params->spp_pathmaxrxt;
+               } else {
+                       sp->pathmaxrxt = params->spp_pathmaxrxt;
+               }
+       }
+
+       return 0;
+}
+
 static int sctp_setsockopt_peer_addr_params(struct sock *sk,
-                                           char *optval, int optlen)
+                                           char __user *optval, int optlen)
 {
-       struct sctp_paddrparams params;
-       struct sctp_transport *trans;
+       struct sctp_paddrparams  params;
+       struct sctp_transport   *trans = NULL;
+       struct sctp_association *asoc = NULL;
+       struct sctp_sock        *sp = sctp_sk(sk);
        int error;
+       int hb_change, pmtud_change, sackdelay_change;
 
        if (optlen != sizeof(struct sctp_paddrparams))
-               return -EINVAL;
+               return - EINVAL;
+
        if (copy_from_user(&params, optval, optlen))
                return -EFAULT;
 
-       trans = sctp_addr_id2transport(sk, &params.spp_address,
-                                      params.spp_assoc_id);
-       if (!trans)
+       /* Validate flags and value parameters. */
+       hb_change        = params.spp_flags & SPP_HB;
+       pmtud_change     = params.spp_flags & SPP_PMTUD;
+       sackdelay_change = params.spp_flags & SPP_SACKDELAY;
+
+       if (hb_change        == SPP_HB ||
+           pmtud_change     == SPP_PMTUD ||
+           sackdelay_change == SPP_SACKDELAY ||
+           params.spp_sackdelay > 500 ||
+           (params.spp_pathmtu
+           && params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
                return -EINVAL;
 
-       /* Applications can enable or disable heartbeats for any peer address
-        * of an association, modify an address's heartbeat interval, force a
-        * heartbeat to be sent immediately, and adjust the address's maximum
-        * number of retransmissions sent before an address is considered
-        * unreachable.
-        *
-        * The value of the heartbeat interval, in milliseconds. A value of
-        * UINT32_MAX (4294967295), when modifying the parameter, specifies
-        * that a heartbeat should be sent immediately to the peer address,
-        * and the current interval should remain unchanged.
-        */
-       if (0xffffffff == params.spp_hbinterval) {
-               error = sctp_primitive_REQUESTHEARTBEAT (trans->asoc, trans);
-               if (error)
-                       return error;
-       } else {
-       /* The value of the heartbeat interval, in milliseconds. A value of 0,
-        * when modifying the parameter, specifies that the heartbeat on this
-        * address should be disabled.
+       /* If an address other than INADDR_ANY is specified, and
+        * no transport is found, then the request is invalid.
         */
-               if (params.spp_hbinterval) {
-                       trans->hb_allowed = 1;
-                       trans->hb_interval = 
-                               MSECS_TO_JIFFIES(params.spp_hbinterval);
-               } else
-                       trans->hb_allowed = 0;
+       if (!sctp_is_any(( union sctp_addr *)&params.spp_address)) {
+               trans = sctp_addr_id2transport(sk, &params.spp_address,
+                                              params.spp_assoc_id);
+               if (!trans)
+                       return -EINVAL;
        }
 
-       /* spp_pathmaxrxt contains the maximum number of retransmissions
-        * before this address shall be considered unreachable.
+       /* Get association, if assoc_id != 0 and the socket is a one
+        * to many style socket, and an association was not found, then
+        * the id was invalid.
+        */
+       asoc = sctp_id2assoc(sk, params.spp_assoc_id);
+       if (!asoc && params.spp_assoc_id && sctp_style(sk, UDP))
+               return -EINVAL;
+
+       /* Heartbeat demand can only be sent on a transport or
+        * association, but not a socket.
+        */
+       if (params.spp_flags & SPP_HB_DEMAND && !trans && !asoc)
+               return -EINVAL;
+
+       /* Process parameters. */
+       error = sctp_apply_peer_addr_params(&params, trans, asoc, sp,
+                                           hb_change, pmtud_change,
+                                           sackdelay_change);
+
+       if (error)
+               return error;
+
+       /* If changes are for association, also apply parameters to each
+        * transport.
         */
-       trans->error_threshold = params.spp_pathmaxrxt;
+       if (!trans && asoc) {
+               struct list_head *pos;
+
+               list_for_each(pos, &asoc->peer.transport_addr_list) {
+                       trans = list_entry(pos, struct sctp_transport,
+                                          transports);
+                       sctp_apply_peer_addr_params(&params, trans, asoc, sp,
+                                                   hb_change, pmtud_change,
+                                                   sackdelay_change);
+               }
+       }
 
        return 0;
 }
 
+/* 7.1.24. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
+ *
+ *   This options will get or set the delayed ack timer.  The time is set
+ *   in milliseconds.  If the assoc_id is 0, then this sets or gets the
+ *   endpoints default delayed ack timer value.  If the assoc_id field is
+ *   non-zero, then the set or get effects the specified association.
+ *
+ *   struct sctp_assoc_value {
+ *       sctp_assoc_t            assoc_id;
+ *       uint32_t                assoc_value;
+ *   };
+ *
+ *     assoc_id    - This parameter, indicates which association the
+ *                   user is preforming an action upon. Note that if
+ *                   this field's value is zero then the endpoints
+ *                   default value is changed (effecting future
+ *                   associations only).
+ *
+ *     assoc_value - This parameter contains the number of milliseconds
+ *                   that the user is requesting the delayed ACK timer
+ *                   be set to. Note that this value is defined in
+ *                   the standard to be between 200 and 500 milliseconds.
+ *
+ *                   Note: a value of zero will leave the value alone,
+ *                   but disable SACK delay. A non-zero value will also
+ *                   enable SACK delay.
+ */
+
+static int sctp_setsockopt_delayed_ack_time(struct sock *sk,
+                                           char __user *optval, int optlen)
+{
+       struct sctp_assoc_value  params;
+       struct sctp_transport   *trans = NULL;
+       struct sctp_association *asoc = NULL;
+       struct sctp_sock        *sp = sctp_sk(sk);
+
+       if (optlen != sizeof(struct sctp_assoc_value))
+               return - EINVAL;
+
+       if (copy_from_user(&params, optval, optlen))
+               return -EFAULT;
+
+       /* Validate value parameter. */
+       if (params.assoc_value > 500)
+               return -EINVAL;
+
+       /* Get association, if assoc_id != 0 and the socket is a one
+        * to many style socket, and an association was not found, then
+        * the id was invalid.
+        */
+       asoc = sctp_id2assoc(sk, params.assoc_id);
+       if (!asoc && params.assoc_id && sctp_style(sk, UDP))
+               return -EINVAL;
+
+       if (params.assoc_value) {
+               if (asoc) {
+                       asoc->sackdelay =
+                               msecs_to_jiffies(params.assoc_value);
+                       asoc->param_flags = 
+                               (asoc->param_flags & ~SPP_SACKDELAY) |
+                               SPP_SACKDELAY_ENABLE;
+               } else {
+                       sp->sackdelay = params.assoc_value;
+                       sp->param_flags = 
+                               (sp->param_flags & ~SPP_SACKDELAY) |
+                               SPP_SACKDELAY_ENABLE;
+               }
+       } else {
+               if (asoc) {
+                       asoc->param_flags = 
+                               (asoc->param_flags & ~SPP_SACKDELAY) |
+                               SPP_SACKDELAY_DISABLE;
+               } else {
+                       sp->param_flags = 
+                               (sp->param_flags & ~SPP_SACKDELAY) |
+                               SPP_SACKDELAY_DISABLE;
+               }
+       }
+
+       /* If change is for association, also apply to each transport. */
+       if (asoc) {
+               struct list_head *pos;
+
+               list_for_each(pos, &asoc->peer.transport_addr_list) {
+                       trans = list_entry(pos, struct sctp_transport,
+                                          transports);
+                       if (params.assoc_value) {
+                               trans->sackdelay =
+                                       msecs_to_jiffies(params.assoc_value);
+                               trans->param_flags = 
+                                       (trans->param_flags & ~SPP_SACKDELAY) |
+                                       SPP_SACKDELAY_ENABLE;
+                       } else {
+                               trans->param_flags = 
+                                       (trans->param_flags & ~SPP_SACKDELAY) |
+                                       SPP_SACKDELAY_DISABLE;
+                       }
+               }
+       }
+       return 0;
+}
+
 /* 7.1.3 Initialization Parameters (SCTP_INITMSG)
  *
  * Applications can specify protocol parameters for the default association
@@ -1686,10 +2385,10 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
  * by the change).  With TCP-style sockets, this option is inherited by
  * sockets derived from a listener socket.
  */
-static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen)
+static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int optlen)
 {
        struct sctp_initmsg sinit;
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
 
        if (optlen != sizeof(struct sctp_initmsg))
                return -EINVAL;
@@ -1723,11 +2422,11 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen)
  *   to this call if the caller is using the UDP model.
  */
 static int sctp_setsockopt_default_send_param(struct sock *sk,
-                                               char *optval, int optlen)
+                                               char __user *optval, int optlen)
 {
        struct sctp_sndrcvinfo info;
        struct sctp_association *asoc;
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
 
        if (optlen != sizeof(struct sctp_sndrcvinfo))
                return -EINVAL;
@@ -1761,7 +2460,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
  * the association primary.  The enclosed address must be one of the
  * association peer's addresses.
  */
-static int sctp_setsockopt_primary_addr(struct sock *sk, char *optval,
+static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
                                        int optlen)
 {
        struct sctp_prim prim;
@@ -1790,14 +2489,14 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char *optval,
  * introduced, at the cost of more packets in the network.  Expects an
  *  integer boolean flag.
  */
-static int sctp_setsockopt_nodelay(struct sock *sk, char *optval,
+static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval,
                                        int optlen)
 {
        int val;
 
        if (optlen < sizeof(int))
                return -EINVAL;
-       if (get_user(val, (int *)optval))
+       if (get_user(val, (int __user *)optval))
                return -EFAULT;
 
        sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1;
@@ -1816,7 +2515,7 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char *optval,
  * be changed.
  *
  */
-static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) {
+static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int optlen) {
        struct sctp_rtoinfo rtoinfo;
        struct sctp_association *asoc;
 
@@ -1835,16 +2534,16 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) {
        if (asoc) {
                if (rtoinfo.srto_initial != 0)
                        asoc->rto_initial = 
-                               MSECS_TO_JIFFIES(rtoinfo.srto_initial);
+                               msecs_to_jiffies(rtoinfo.srto_initial);
                if (rtoinfo.srto_max != 0)
-                       asoc->rto_max = MSECS_TO_JIFFIES(rtoinfo.srto_max);
+                       asoc->rto_max = msecs_to_jiffies(rtoinfo.srto_max);
                if (rtoinfo.srto_min != 0)
-                       asoc->rto_min = MSECS_TO_JIFFIES(rtoinfo.srto_min);
+                       asoc->rto_min = msecs_to_jiffies(rtoinfo.srto_min);
        } else {
                /* If there is no association or the association-id = 0
                 * set the values to the endpoint.
                 */
-               struct sctp_opt *sp = sctp_sk(sk);
+               struct sctp_sock *sp = sctp_sk(sk);
 
                if (rtoinfo.srto_initial != 0)
                        sp->rtoinfo.srto_initial = rtoinfo.srto_initial;
@@ -1868,7 +2567,7 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) {
  * See [SCTP] for more information.
  *
  */
-static int sctp_setsockopt_associnfo(struct sock *sk, char *optval, int optlen)
+static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int optlen)
 {
 
        struct sctp_assocparams assocparams;
@@ -1886,8 +2585,32 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char *optval, int optlen)
 
        /* 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;
@@ -1897,7 +2620,7 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char *optval, int optlen)
                }
        } else {
                /* Set the values to the endpoint */
-               struct sctp_opt *sp = sctp_sk(sk);
+               struct sctp_sock *sp = sctp_sk(sk);
 
                if (assocparams.sasoc_asocmaxrxt != 0)
                        sp->assocparams.sasoc_asocmaxrxt =
@@ -1919,14 +2642,14 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char *optval, int optlen)
  * addresses and a user will receive both PF_INET6 and PF_INET type
  * addresses on the socket.
  */
-static int sctp_setsockopt_mappedv4(struct sock *sk, char *optval, int optlen)
+static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int optlen)
 {
        int val;
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
 
        if (optlen < sizeof(int))
                return -EINVAL;
-       if (get_user(val, (int *)optval))
+       if (get_user(val, (int __user *)optval))
                return -EFAULT;
        if (val)
                sp->v4mapped = 1;
@@ -1946,27 +2669,25 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char *optval, int optlen)
  * PMTU of the underlying association is smaller than the value set by
  * the user.
  */
-static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen)
+static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen)
 {
        struct sctp_association *asoc;
        struct list_head *pos;
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
        int val;
 
        if (optlen < sizeof(int))
                return -EINVAL;
-       if (get_user(val, (int *)optval))
+       if (get_user(val, (int __user *)optval))
                return -EFAULT;
-       if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN))
+       if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)))
                return -EINVAL;
        sp->user_frag = val;
 
-       if (val) {
-               /* Update the frag_point of the existing associations. */
-               list_for_each(pos, &(sp->ep->asocs)) {
-                       asoc = list_entry(pos, struct sctp_association, asocs);
-                       asoc->frag_point = sctp_frag_point(sp, asoc->pmtu); 
-               }
+       /* Update the frag_point of the existing associations. */
+       list_for_each(pos, &(sp->ep->asocs)) {
+               asoc = list_entry(pos, struct sctp_association, asocs);
+               asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); 
        }
 
        return 0;
@@ -1981,10 +2702,10 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen)
  *   locally bound addresses. The following structure is used to make a
  *   set primary request:
  */
-static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
+static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval,
                                             int optlen)
 {
-       struct sctp_opt         *sp;
+       struct sctp_sock        *sp;
        struct sctp_endpoint    *ep;
        struct sctp_association *asoc = NULL;
        struct sctp_setpeerprim prim;
@@ -2032,6 +2753,20 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
        return err;
 }
 
+static int sctp_setsockopt_adaption_layer(struct sock *sk, char __user *optval,
+                                         int optlen)
+{
+       struct sctp_setadaption adaption;
+
+       if (optlen != sizeof(struct sctp_setadaption))
+               return -EINVAL;
+       if (copy_from_user(&adaption, optval, optlen)) 
+               return -EFAULT;
+
+       sctp_sk(sk)->adaption_ind = adaption.ssb_adaption_ind;
+
+       return 0;
+}
 
 /* API 6.2 setsockopt(), getsockopt()
  *
@@ -2041,9 +2776,9 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
  *
  * The syntax is:
  *
- *   ret = getsockopt(int sd, int level, int optname, void *optval,
- *                    int *optlen);
- *   ret = setsockopt(int sd, int level, int optname, const void *optval,
+ *   ret = getsockopt(int sd, int level, int optname, void __user *optval,
+ *                    int __user *optlen);
+ *   ret = setsockopt(int sd, int level, int optname, const void __user *optval,
  *                    int optlen);
  *
  *   sd      - the socket descript.
@@ -2053,7 +2788,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
  *   optlen  - the size of the buffer.
  */
 SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
-                               char *optval, int optlen)
+                               char __user *optval, int optlen)
 {
        int retval = 0;
 
@@ -2077,16 +2812,22 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
        switch (optname) {
        case SCTP_SOCKOPT_BINDX_ADD:
                /* 'optlen' is the size of the addresses buffer. */
-               retval = sctp_setsockopt_bindx(sk, (struct sockaddr *)optval,
+               retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval,
                                               optlen, SCTP_BINDX_ADD_ADDR);
                break;
 
        case SCTP_SOCKOPT_BINDX_REM:
                /* 'optlen' is the size of the addresses buffer. */
-               retval = sctp_setsockopt_bindx(sk, (struct sockaddr *)optval,
+               retval = sctp_setsockopt_bindx(sk, (struct sockaddr __user *)optval,
                                               optlen, SCTP_BINDX_REM_ADDR);
                break;
 
+       case SCTP_SOCKOPT_CONNECTX:
+               /* 'optlen' is the size of the addresses buffer. */
+               retval = sctp_setsockopt_connectx(sk, (struct sockaddr __user *)optval,
+                                              optlen);
+               break;
+
        case SCTP_DISABLE_FRAGMENTS:
                retval = sctp_setsockopt_disable_fragments(sk, optval, optlen);
                break;
@@ -2103,6 +2844,10 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
                retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen);
                break;
 
+       case SCTP_DELAYED_ACK_TIME:
+               retval = sctp_setsockopt_delayed_ack_time(sk, optval, optlen);
+               break;
+
        case SCTP_INITMSG:
                retval = sctp_setsockopt_initmsg(sk, optval, optlen);
                break;
@@ -2131,6 +2876,10 @@ 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);
+               break;
+
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -2158,112 +2907,29 @@ out_nounlock:
  *
  * len: the size of the address.
  */
-SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
+SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr,
                             int addr_len)
 {
-       struct sctp_opt *sp;
-       struct sctp_endpoint *ep;
-       struct sctp_association *asoc;
-       struct sctp_transport *transport;
-       union sctp_addr to;
-       struct sctp_af *af;
-       sctp_scope_t scope;
-       long timeo;
        int err = 0;
+       struct sctp_af *af;
 
        sctp_lock_sock(sk);
 
-       SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d)\n",
-                         __FUNCTION__, sk, uaddr, addr_len);
-
-       sp = sctp_sk(sk);
-       ep = sp->ep;
-
-       /* connect() cannot be done on a socket that is already in ESTABLISHED
-        * state - UDP-style peeled off socket or a TCP-style socket that
-        * is already connected.
-        * It cannot be done even on a TCP-style listening socket.
-        */
-       if (sctp_sstate(sk, ESTABLISHED) ||
-           (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) {
-               err = -EISCONN;
-               goto out_unlock;
-       }
-
-       err = sctp_verify_addr(sk, (union sctp_addr *)uaddr, addr_len);
-       if (err)
-               goto out_unlock;
-
-       if (addr_len > sizeof(to))
-               addr_len = sizeof(to);
-       memcpy(&to, uaddr, addr_len);
-       to.v4.sin_port = ntohs(to.v4.sin_port);
-
-       asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport);
-       if (asoc) {
-               if (asoc->state >= SCTP_STATE_ESTABLISHED)
-                       err = -EISCONN;
-               else
-                       err = -EALREADY;
-               goto out_unlock;
-       }
-
-       /* If we could not find a matching association on the endpoint,
-        * 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)) {
-               err = -EADDRNOTAVAIL;
-               goto out_unlock;
-       }
-
-       /* If a bind() or sctp_bindx() is not called prior to a connect()
-        * call, the system picks an ephemeral port and will choose an address
-        * set equivalent to binding with a wildcard address.
-        */
-       if (!ep->base.bind_addr.port) {
-               if (sctp_autobind(sk)) {
-                       err = -EAGAIN;
-                       goto out_unlock;
-               }
-       }
-
-       scope = sctp_scope(&to);
-       asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);
-       if (!asoc) {
-               err = -ENOMEM;
-               goto out_unlock;
-       }
-
-       /* Prime the peer's transport structures.  */
-       transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL);
-       if (!transport) {
-               sctp_association_free(asoc);
-               goto out_unlock;
-       }
-       err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL);
-       if (err < 0) {
-               sctp_association_free(asoc);
-               goto out_unlock;
-       }
+       SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d\n",
+                         __FUNCTION__, sk, addr, addr_len);
 
-       err = sctp_primitive_ASSOCIATE(asoc, NULL);
-       if (err < 0) {
-               sctp_association_free(asoc);
-               goto out_unlock;
+       /* Validate addr_len before calling common connect/connectx routine. */
+       af = sctp_get_af_specific(addr->sa_family);
+       if (!af || addr_len < af->sockaddr_len) {
+               err = -EINVAL;
+       } else {
+               /* Pass correct addr len to common routine (so it knows there
+                * is only one address being passed.
+                */
+               err = __sctp_connect(sk, addr, af->sockaddr_len);
        }
 
-       /* Initialize sk's dport and daddr for getpeername() */
-       inet_sk(sk)->dport = htons(asoc->peer.port);
-       af = sctp_get_af_specific(to.sa.sa_family);
-       af->to_sk_daddr(&to, sk);
-
-       timeo = sock_sndtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK);
-       err = sctp_wait_for_connect(asoc, &timeo);
-
-out_unlock:
        sctp_release_sock(sk);
-
        return err;
 }
 
@@ -2282,7 +2948,7 @@ SCTP_STATIC int sctp_disconnect(struct sock *sk, int flags)
  */
 SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err)
 {
-       struct sctp_opt *sp;
+       struct sctp_sock *sp;
        struct sctp_endpoint *ep;
        struct sock *newsk = NULL;
        struct sctp_association *asoc;
@@ -2345,7 +3011,7 @@ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 SCTP_STATIC int sctp_init_sock(struct sock *sk)
 {
        struct sctp_endpoint *ep;
-       struct sctp_opt *sp;
+       struct sctp_sock *sp;
 
        SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk);
 
@@ -2379,14 +3045,14 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        sp->initmsg.sinit_num_ostreams   = sctp_max_outstreams;
        sp->initmsg.sinit_max_instreams  = sctp_max_instreams;
        sp->initmsg.sinit_max_attempts   = sctp_max_retrans_init;
-       sp->initmsg.sinit_max_init_timeo = JIFFIES_TO_MSECS(sctp_rto_max);
+       sp->initmsg.sinit_max_init_timeo = jiffies_to_msecs(sctp_rto_max);
 
        /* Initialize default RTO related parameters.  These parameters can
         * be modified for with the SCTP_RTOINFO socket option.
         */
-       sp->rtoinfo.srto_initial = JIFFIES_TO_MSECS(sctp_rto_initial);
-       sp->rtoinfo.srto_max     = JIFFIES_TO_MSECS(sctp_rto_max);
-       sp->rtoinfo.srto_min     = JIFFIES_TO_MSECS(sctp_rto_min);
+       sp->rtoinfo.srto_initial = jiffies_to_msecs(sctp_rto_initial);
+       sp->rtoinfo.srto_max     = jiffies_to_msecs(sctp_rto_max);
+       sp->rtoinfo.srto_min     = jiffies_to_msecs(sctp_rto_min);
 
        /* Initialize default association related parameters. These parameters
         * can be modified with the SCTP_ASSOCINFO socket option.
@@ -2396,7 +3062,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        sp->assocparams.sasoc_peer_rwnd = 0;
        sp->assocparams.sasoc_local_rwnd = 0;
        sp->assocparams.sasoc_cookie_life = 
-               JIFFIES_TO_MSECS(sctp_valid_cookie_life);
+               jiffies_to_msecs(sctp_valid_cookie_life);
 
        /* Initialize default event subscriptions. By default, all the
         * options are off. 
@@ -2406,8 +3072,13 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        /* Default Peer Address Parameters.  These defaults can
         * be modified via SCTP_PEER_ADDR_PARAMS
         */
-       sp->paddrparam.spp_hbinterval = JIFFIES_TO_MSECS(sctp_hb_interval);
-       sp->paddrparam.spp_pathmaxrxt = sctp_max_retrans_path;
+       sp->hbinterval  = jiffies_to_msecs(sctp_hb_interval);
+       sp->pathmaxrxt  = sctp_max_retrans_path;
+       sp->pathmtu     = 0; // allow default discovery
+       sp->sackdelay   = jiffies_to_msecs(sctp_sack_timeout);
+       sp->param_flags = SPP_HB_ENABLE |
+                         SPP_PMTUD_ENABLE |
+                         SPP_SACKDELAY_ENABLE;
 
        /* If enabled no SCTP message fragmentation will be performed.
         * Configure through SCTP_DISABLE_FRAGMENTS socket option.
@@ -2430,6 +3101,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        /* User specified fragmentation limit. */
        sp->user_frag         = 0;
 
+       sp->adaption_ind = 0;
+
        sp->pf = sctp_get_pf_specific(sk->sk_family);
 
        /* Control variables for partial data delivery. */
@@ -2506,8 +3179,9 @@ SCTP_STATIC void sctp_shutdown(struct sock *sk, int how)
  * number of unacked data chunks, and number of data chunks pending
  * receipt.  This information is read-only.
  */
-static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
-                                      int *optlen)
+static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
+                                      char __user *optval,
+                                      int __user *optlen)
 {
        struct sctp_status status;
        struct sctp_association *asoc = NULL;
@@ -2549,18 +3223,21 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
        /* 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);
-       status.sstat_primary.spinfo_state = transport->active;
+       status.sstat_primary.spinfo_state = transport->state;
        status.sstat_primary.spinfo_cwnd = transport->cwnd;
        status.sstat_primary.spinfo_srtt = transport->srtt;
-       status.sstat_primary.spinfo_rto = JIFFIES_TO_MSECS(transport->rto);
-       status.sstat_primary.spinfo_mtu = transport->pmtu;
+       status.sstat_primary.spinfo_rto = jiffies_to_msecs(transport->rto);
+       status.sstat_primary.spinfo_mtu = transport->pathmtu;
+
+       if (status.sstat_primary.spinfo_state == SCTP_UNKNOWN)
+               status.sstat_primary.spinfo_state = SCTP_ACTIVE;
 
        if (put_user(len, optlen)) {
                retval = -EFAULT;
                goto out;
        }
 
-       SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %p\n",
+       SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %d\n",
                          len, status.sstat_state, status.sstat_rwnd,
                          status.sstat_assoc_id);
 
@@ -2582,7 +3259,8 @@ out:
  * read-only.
  */
 static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,
-                                         char *optval, int *optlen)
+                                         char __user *optval,
+                                         int __user *optlen)
 {
        struct sctp_paddrinfo pinfo;
        struct sctp_transport *transport;
@@ -2604,11 +3282,14 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,
                return -EINVAL;
 
        pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
-       pinfo.spinfo_state = transport->active;
+       pinfo.spinfo_state = transport->state;
        pinfo.spinfo_cwnd = transport->cwnd;
        pinfo.spinfo_srtt = transport->srtt;
-       pinfo.spinfo_rto = JIFFIES_TO_MSECS(transport->rto);
-       pinfo.spinfo_mtu = transport->pmtu;
+       pinfo.spinfo_rto = jiffies_to_msecs(transport->rto);
+       pinfo.spinfo_mtu = transport->pathmtu;
+
+       if (pinfo.spinfo_state == SCTP_UNKNOWN)
+               pinfo.spinfo_state = SCTP_ACTIVE;
 
        if (put_user(len, optlen)) {
                retval = -EFAULT;
@@ -2632,7 +3313,7 @@ out:
  * instead a error will be indicated to the user.
  */
 static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
-                                                   char *optval, int *optlen)
+                                       char __user *optval, int __user *optlen)
 {
        int val;
 
@@ -2653,8 +3334,8 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
  * This socket option is used to specify various notifications and
  * ancillary data the user wishes to receive.
  */
-static int sctp_getsockopt_events(struct sock *sk, int len, char *optval,
-                                 int *optlen)
+static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval,
+                                 int __user *optlen)
 {
        if (len != sizeof(struct sctp_event_subscribe))
                return -EINVAL;
@@ -2674,7 +3355,7 @@ static int sctp_getsockopt_events(struct sock *sk, int len, char *optval,
  * integer defining the number of seconds of idle time before an
  * association is closed.
  */
-static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen)
+static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optval, int __user *optlen)
 {
        /* Applicable to UDP-style socket only */
        if (sctp_style(sk, TCP))
@@ -2714,7 +3395,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
        return err;
 }
 
-static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen)
+static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen)
 {
        sctp_peeloff_arg_t peeloff;
        struct socket *newsock;
@@ -2767,56 +3448,226 @@ out:
  * address's parameters:
  *
  *  struct sctp_paddrparams {
- *      sctp_assoc_t            spp_assoc_id;
- *      struct sockaddr_storage spp_address;
- *      uint32_t                spp_hbinterval;
- *      uint16_t                spp_pathmaxrxt;
- *  };
- *
- *   spp_assoc_id    - (UDP style socket) This is filled in the application,
- *                     and identifies the association for this query.
+ *     sctp_assoc_t            spp_assoc_id;
+ *     struct sockaddr_storage spp_address;
+ *     uint32_t                spp_hbinterval;
+ *     uint16_t                spp_pathmaxrxt;
+ *     uint32_t                spp_pathmtu;
+ *     uint32_t                spp_sackdelay;
+ *     uint32_t                spp_flags;
+ * };
+ *
+ *   spp_assoc_id    - (one-to-many style socket) This is filled in the
+ *                     application, and identifies the association for
+ *                     this query.
  *   spp_address     - This specifies which address is of interest.
  *   spp_hbinterval  - This contains the value of the heartbeat interval,
- *                     in milliseconds.  A value of 0, when modifying the
- *                     parameter, specifies that the heartbeat on this
- *                     address should be disabled. A value of UINT32_MAX
- *                     (4294967295), when modifying the parameter,
- *                     specifies that a heartbeat should be sent
- *                     immediately to the peer address, and the current
- *                     interval should remain unchanged.
+ *                     in milliseconds.  If a  value of zero
+ *                     is present in this field then no changes are to
+ *                     be made to this parameter.
  *   spp_pathmaxrxt  - This contains the maximum number of
  *                     retransmissions before this address shall be
- *                     considered unreachable.
+ *                     considered unreachable. If a  value of zero
+ *                     is present in this field then no changes are to
+ *                     be made to this parameter.
+ *   spp_pathmtu     - When Path MTU discovery is disabled the value
+ *                     specified here will be the "fixed" path mtu.
+ *                     Note that if the spp_address field is empty
+ *                     then all associations on this address will
+ *                     have this fixed path mtu set upon them.
+ *
+ *   spp_sackdelay   - When delayed sack is enabled, this value specifies
+ *                     the number of milliseconds that sacks will be delayed
+ *                     for. This value will apply to all addresses of an
+ *                     association if the spp_address field is empty. Note
+ *                     also, that if delayed sack is enabled and this
+ *                     value is set to 0, no change is made to the last
+ *                     recorded delayed sack timer value.
+ *
+ *   spp_flags       - These flags are used to control various features
+ *                     on an association. The flag field may contain
+ *                     zero or more of the following options.
+ *
+ *                     SPP_HB_ENABLE  - Enable heartbeats on the
+ *                     specified address. Note that if the address
+ *                     field is empty all addresses for the association
+ *                     have heartbeats enabled upon them.
+ *
+ *                     SPP_HB_DISABLE - Disable heartbeats on the
+ *                     speicifed address. Note that if the address
+ *                     field is empty all addresses for the association
+ *                     will have their heartbeats disabled. Note also
+ *                     that SPP_HB_ENABLE and SPP_HB_DISABLE are
+ *                     mutually exclusive, only one of these two should
+ *                     be specified. Enabling both fields will have
+ *                     undetermined results.
+ *
+ *                     SPP_HB_DEMAND - Request a user initiated heartbeat
+ *                     to be made immediately.
+ *
+ *                     SPP_PMTUD_ENABLE - This field will enable PMTU
+ *                     discovery upon the specified address. Note that
+ *                     if the address feild is empty then all addresses
+ *                     on the association are effected.
+ *
+ *                     SPP_PMTUD_DISABLE - This field will disable PMTU
+ *                     discovery upon the specified address. Note that
+ *                     if the address feild is empty then all addresses
+ *                     on the association are effected. Not also that
+ *                     SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE are mutually
+ *                     exclusive. Enabling both will have undetermined
+ *                     results.
+ *
+ *                     SPP_SACKDELAY_ENABLE - Setting this flag turns
+ *                     on delayed sack. The time specified in spp_sackdelay
+ *                     is used to specify the sack delay for this address. Note
+ *                     that if spp_address is empty then all addresses will
+ *                     enable delayed sack and take on the sack delay
+ *                     value specified in spp_sackdelay.
+ *                     SPP_SACKDELAY_DISABLE - Setting this flag turns
+ *                     off delayed sack. If the spp_address field is blank then
+ *                     delayed sack is disabled for the entire association. Note
+ *                     also that this field is mutually exclusive to
+ *                     SPP_SACKDELAY_ENABLE, setting both will have undefined
+ *                     results.
  */
 static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
-                                               char *optval, int *optlen)
+                                           char __user *optval, int __user *optlen)
 {
-       struct sctp_paddrparams params;
-       struct sctp_transport *trans;
+       struct sctp_paddrparams  params;
+       struct sctp_transport   *trans = NULL;
+       struct sctp_association *asoc = NULL;
+       struct sctp_sock        *sp = sctp_sk(sk);
 
        if (len != sizeof(struct sctp_paddrparams))
                return -EINVAL;
-       if (copy_from_user(&params, optval, *optlen))
+
+       if (copy_from_user(&params, optval, len))
+               return -EFAULT;
+
+       /* If an address other than INADDR_ANY is specified, and
+        * no transport is found, then the request is invalid.
+        */
+       if (!sctp_is_any(( union sctp_addr *)&params.spp_address)) {
+               trans = sctp_addr_id2transport(sk, &params.spp_address,
+                                              params.spp_assoc_id);
+               if (!trans) {
+                       SCTP_DEBUG_PRINTK("Failed no transport\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* Get association, if assoc_id != 0 and the socket is a one
+        * to many style socket, and an association was not found, then
+        * the id was invalid.
+        */
+       asoc = sctp_id2assoc(sk, params.spp_assoc_id);
+       if (!asoc && params.spp_assoc_id && sctp_style(sk, UDP)) {
+               SCTP_DEBUG_PRINTK("Failed no association\n");
+               return -EINVAL;
+       }
+
+       if (trans) {
+               /* Fetch transport values. */
+               params.spp_hbinterval = jiffies_to_msecs(trans->hbinterval);
+               params.spp_pathmtu    = trans->pathmtu;
+               params.spp_pathmaxrxt = trans->pathmaxrxt;
+               params.spp_sackdelay  = jiffies_to_msecs(trans->sackdelay);
+
+               /*draft-11 doesn't say what to return in spp_flags*/
+               params.spp_flags      = trans->param_flags;
+       } else if (asoc) {
+               /* Fetch association values. */
+               params.spp_hbinterval = jiffies_to_msecs(asoc->hbinterval);
+               params.spp_pathmtu    = asoc->pathmtu;
+               params.spp_pathmaxrxt = asoc->pathmaxrxt;
+               params.spp_sackdelay  = jiffies_to_msecs(asoc->sackdelay);
+
+               /*draft-11 doesn't say what to return in spp_flags*/
+               params.spp_flags      = asoc->param_flags;
+       } else {
+               /* Fetch socket values. */
+               params.spp_hbinterval = sp->hbinterval;
+               params.spp_pathmtu    = sp->pathmtu;
+               params.spp_sackdelay  = sp->sackdelay;
+               params.spp_pathmaxrxt = sp->pathmaxrxt;
+
+               /*draft-11 doesn't say what to return in spp_flags*/
+               params.spp_flags      = sp->param_flags;
+       }
+
+       if (copy_to_user(optval, &params, len))
+               return -EFAULT;
+
+       if (put_user(len, optlen))
+               return -EFAULT;
+
+       return 0;
+}
+
+/* 7.1.24. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
+ *
+ *   This options will get or set the delayed ack timer.  The time is set
+ *   in milliseconds.  If the assoc_id is 0, then this sets or gets the
+ *   endpoints default delayed ack timer value.  If the assoc_id field is
+ *   non-zero, then the set or get effects the specified association.
+ *
+ *   struct sctp_assoc_value {
+ *       sctp_assoc_t            assoc_id;
+ *       uint32_t                assoc_value;
+ *   };
+ *
+ *     assoc_id    - This parameter, indicates which association the
+ *                   user is preforming an action upon. Note that if
+ *                   this field's value is zero then the endpoints
+ *                   default value is changed (effecting future
+ *                   associations only).
+ *
+ *     assoc_value - This parameter contains the number of milliseconds
+ *                   that the user is requesting the delayed ACK timer
+ *                   be set to. Note that this value is defined in
+ *                   the standard to be between 200 and 500 milliseconds.
+ *
+ *                   Note: a value of zero will leave the value alone,
+ *                   but disable SACK delay. A non-zero value will also
+ *                   enable SACK delay.
+ */
+static int sctp_getsockopt_delayed_ack_time(struct sock *sk, int len,
+                                           char __user *optval,
+                                           int __user *optlen)
+{
+       struct sctp_assoc_value  params;
+       struct sctp_association *asoc = NULL;
+       struct sctp_sock        *sp = sctp_sk(sk);
+
+       if (len != sizeof(struct sctp_assoc_value))
+               return - EINVAL;
+
+       if (copy_from_user(&params, optval, len))
                return -EFAULT;
 
-       trans = sctp_addr_id2transport(sk, &params.spp_address,
-                                      params.spp_assoc_id);
-       if (!trans)
+       /* Get association, if assoc_id != 0 and the socket is a one
+        * to many style socket, and an association was not found, then
+        * the id was invalid.
+        */
+       asoc = sctp_id2assoc(sk, params.assoc_id);
+       if (!asoc && params.assoc_id && sctp_style(sk, UDP))
                return -EINVAL;
 
-       /* The value of the heartbeat interval, in milliseconds. A value of 0,
-        * when modifying the parameter, specifies that the heartbeat on this
-        * address should be disabled.
-        */
-       if (!trans->hb_allowed)
-               params.spp_hbinterval = 0;
-       else
-               params.spp_hbinterval = JIFFIES_TO_MSECS(trans->hb_interval);
-
-       /* spp_pathmaxrxt contains the maximum number of retransmissions
-        * before this address shall be considered unreachable.
-        */
-       params.spp_pathmaxrxt = trans->error_threshold;
+       if (asoc) {
+               /* Fetch association values. */
+               if (asoc->param_flags & SPP_SACKDELAY_ENABLE)
+                       params.assoc_value = jiffies_to_msecs(
+                               asoc->sackdelay);
+               else
+                       params.assoc_value = 0;
+       } else {
+               /* Fetch socket values. */
+               if (sp->param_flags & SPP_SACKDELAY_ENABLE)
+                       params.assoc_value  = sp->sackdelay;
+               else
+                       params.assoc_value  = 0;
+       }
 
        if (copy_to_user(optval, &params, len))
                return -EFAULT;
@@ -2838,7 +3689,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
  * by the change).  With TCP-style sockets, this option is inherited by
  * sockets derived from a listener socket.
  */
-static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen)
+static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen)
 {
        if (len != sizeof(struct sctp_initmsg))
                return -EINVAL;
@@ -2847,8 +3698,9 @@ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *
        return 0;
 }
 
-static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len,
-                                         char *optval, int *optlen)
+static int sctp_getsockopt_peer_addrs_num_old(struct sock *sk, int len,
+                                             char __user *optval,
+                                             int __user *optlen)
 {
        sctp_assoc_t id;
        struct sctp_association *asoc;
@@ -2873,23 +3725,28 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len,
        return cnt;
 }
 
-static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
-                                     char *optval, int *optlen)
+/* 
+ * Old API for getting list of peer addresses. Does not work for 32-bit
+ * programs running on a 64-bit kernel
+ */
+static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len,
+                                         char __user *optval,
+                                         int __user *optlen)
 {
        struct sctp_association *asoc;
        struct list_head *pos;
        int cnt = 0;
-       struct sctp_getaddrs getaddrs;
+       struct sctp_getaddrs_old getaddrs;
        struct sctp_transport *from;
-       void *to;
+       void __user *to;
        union sctp_addr temp;
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
        int addrlen;
 
-       if (len != sizeof(struct sctp_getaddrs))
+       if (len != sizeof(struct sctp_getaddrs_old))
                return -EINVAL;
 
-       if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
+       if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old)))
                return -EFAULT;
 
        if (getaddrs.addr_num <= 0) return -EINVAL;
@@ -2899,7 +3756,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
        if (!asoc)
                return -EINVAL;
 
-       to = (void *)getaddrs.addrs;
+       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, sizeof(temp));
@@ -2913,19 +3770,77 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
                if (cnt >= getaddrs.addr_num) break;
        }
        getaddrs.addr_num = cnt;
-       if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs)))
+       if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
+                                     char __user *optval, int __user *optlen)
+{
+       struct sctp_association *asoc;
+       struct list_head *pos;
+       int cnt = 0;
+       struct sctp_getaddrs getaddrs;
+       struct sctp_transport *from;
+       void __user *to;
+       union sctp_addr temp;
+       struct sctp_sock *sp = sctp_sk(sk);
+       int addrlen;
+       size_t space_left;
+       int bytes_copied;
+
+       if (len < sizeof(struct sctp_getaddrs))
+               return -EINVAL;
+
+       if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
+               return -EFAULT;
+
+       /* For UDP-style sockets, id specifies the association to query.  */
+       asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
+       if (!asoc)
+               return -EINVAL;
+
+       to = optval + offsetof(struct sctp_getaddrs,addrs);
+       space_left = len - sizeof(struct sctp_getaddrs) - 
+                       offsetof(struct sctp_getaddrs,addrs);
+
+       list_for_each(pos, &asoc->peer.transport_addr_list) {
+               from = list_entry(pos, struct sctp_transport, transports);
+               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;
+               cnt++;
+               space_left -= addrlen;
+       }
+
+       if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num))
+               return -EFAULT;
+       bytes_copied = ((char __user *)to) - optval;
+       if (put_user(bytes_copied, optlen))
                return -EFAULT;
 
        return 0;
 }
 
-static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len,
-                                               char *optval, int *optlen)
+static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
+                                              char __user *optval,
+                                              int __user *optlen)
 {
        sctp_assoc_t id;
        struct sctp_bind_addr *bp;
        struct sctp_association *asoc;
        struct list_head *pos;
+       struct sctp_sockaddr_entry *addr;
+       rwlock_t *addr_lock;
+       unsigned long flags;
        int cnt = 0;
 
        if (len != sizeof(sctp_assoc_t))
@@ -2942,38 +3857,149 @@ static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len,
         */
        if (0 == id) {
                bp = &sctp_sk(sk)->ep->base.bind_addr;
+               addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
        } else {
                asoc = sctp_id2assoc(sk, id);
                if (!asoc)
                        return -EINVAL;
                bp = &asoc->base.bind_addr;
+               addr_lock = &asoc->base.addr_lock;
+       }
+
+       sctp_read_lock(addr_lock);
+
+       /* If the endpoint is bound to 0.0.0.0 or ::0, count the valid
+        * addresses from the global local address list.
+        */
+       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)) {
+                       sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
+                       list_for_each(pos, &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)) 
+                                       continue;
+                               cnt++;
+                       }
+                       sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
+                                                   flags);
+               } else {
+                       cnt = 1;
+               }
+               goto done;
        }
 
        list_for_each(pos, &bp->address_list) {
                cnt ++;
        }
 
+done:
+       sctp_read_unlock(addr_lock);
        return cnt;
 }
 
-static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
-                                       char *optval, int *optlen)
+/* Helper function that copies local addresses to user and returns the number
+ * of addresses copied.
+ */
+static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs,
+                                       void __user *to)
+{
+       struct list_head *pos;
+       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) {
+               addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+               if ((PF_INET == sk->sk_family) && 
+                   (AF_INET6 == addr->a.sa.sa_family))
+                       continue;
+               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);
+                       return -EFAULT;
+               }
+               to += addrlen;
+               cnt ++;
+               if (cnt >= max_addrs) break;
+       }
+       sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
+
+       return cnt;
+}
+
+static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
+                                   void __user **to, size_t space_left)
+{
+       struct list_head *pos;
+       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) {
+               addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+               if ((PF_INET == sk->sk_family) && 
+                   (AF_INET6 == addr->a.sa.sa_family))
+                       continue;
+               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);
+                       return -EFAULT;
+               }
+               *to += addrlen;
+               cnt ++;
+               space_left -= addrlen;
+       }
+       sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
+
+       return cnt;
+}
+
+/* Old API for getting list of local addresses. Does not work for 32-bit
+ * programs running on a 64-bit kernel
+ */
+static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
+                                          char __user *optval, int __user *optlen)
 {
        struct sctp_bind_addr *bp;
        struct sctp_association *asoc;
        struct list_head *pos;
        int cnt = 0;
-       struct sctp_getaddrs getaddrs;
-       struct sctp_sockaddr_entry *from;
-       void *to;
+       struct sctp_getaddrs_old getaddrs;
+       struct sctp_sockaddr_entry *addr;
+       void __user *to;
        union sctp_addr temp;
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
        int addrlen;
+       rwlock_t *addr_lock;
+       int err = 0;
 
-       if (len != sizeof(struct sctp_getaddrs))
+       if (len != sizeof(struct sctp_getaddrs_old))
                return -EINVAL;
 
-       if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
+       if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old)))
                return -EFAULT;
 
        if (getaddrs.addr_num <= 0) return -EINVAL;
@@ -2985,33 +4011,153 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
         */
        if (0 == getaddrs.assoc_id) {
                bp = &sctp_sk(sk)->ep->base.bind_addr;
+               addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
        } else {
                asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
                if (!asoc)
                        return -EINVAL;
                bp = &asoc->base.bind_addr;
+               addr_lock = &asoc->base.addr_lock;
+       }
+
+       to = getaddrs.addrs;
+
+       sctp_read_lock(addr_lock);
+
+       /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
+        * addresses from the global local address list.
+        */
+       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)) {
+                       cnt = sctp_copy_laddrs_to_user_old(sk, bp->port,
+                                                          getaddrs.addr_num,
+                                                          to);
+                       if (cnt < 0) {
+                               err = cnt;
+                               goto unlock;
+                       }
+                       goto copy_getaddrs;             
+               }
        }
 
-       to = (void *)getaddrs.addrs;
        list_for_each(pos, &bp->address_list) {
-               from = list_entry(pos,
-                               struct sctp_sockaddr_entry,
-                               list);
-               memcpy(&temp, &from->a, sizeof(temp));
+               addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+               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))
-                       return -EFAULT;
+               if (copy_to_user(to, &temp, addrlen)) {
+                       err = -EFAULT;
+                       goto unlock;
+               }
                to += addrlen;
                cnt ++;
                if (cnt >= getaddrs.addr_num) break;
        }
+
+copy_getaddrs:
        getaddrs.addr_num = cnt;
-       if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs)))
+       if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old)))
+               err = -EFAULT;
+
+unlock:
+       sctp_read_unlock(addr_lock);
+       return err;
+}
+
+static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
+                                      char __user *optval, int __user *optlen)
+{
+       struct sctp_bind_addr *bp;
+       struct sctp_association *asoc;
+       struct list_head *pos;
+       int cnt = 0;
+       struct sctp_getaddrs getaddrs;
+       struct sctp_sockaddr_entry *addr;
+       void __user *to;
+       union sctp_addr temp;
+       struct sctp_sock *sp = sctp_sk(sk);
+       int addrlen;
+       rwlock_t *addr_lock;
+       int err = 0;
+       size_t space_left;
+       int bytes_copied;
+
+       if (len <= sizeof(struct sctp_getaddrs))
+               return -EINVAL;
+
+       if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
                return -EFAULT;
 
-       return 0;
+       /*
+        *  For UDP-style sockets, id specifies the association to query.
+        *  If the id field is set to the value '0' then the locally bound
+        *  addresses are returned without regard to any particular
+        *  association.
+        */
+       if (0 == getaddrs.assoc_id) {
+               bp = &sctp_sk(sk)->ep->base.bind_addr;
+               addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
+       } else {
+               asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
+               if (!asoc)
+                       return -EINVAL;
+               bp = &asoc->base.bind_addr;
+               addr_lock = &asoc->base.addr_lock;
+       }
+
+       to = optval + offsetof(struct sctp_getaddrs,addrs);
+       space_left = len - sizeof(struct sctp_getaddrs) -
+                        offsetof(struct sctp_getaddrs,addrs);
+
+       sctp_read_lock(addr_lock);
+
+       /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
+        * addresses from the global local address list.
+        */
+       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)) {
+                       cnt = sctp_copy_laddrs_to_user(sk, bp->port,
+                                                      &to, space_left);
+                       if (cnt < 0) {
+                               err = cnt;
+                               goto unlock;
+                       }
+                       goto copy_getaddrs;             
+               }
+       }
+
+       list_for_each(pos, &bp->address_list) {
+               addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+               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;
+               }
+               to += addrlen;
+               cnt ++;
+               space_left -= addrlen;
+       }
+
+copy_getaddrs:
+       if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num))
+               return -EFAULT;
+       bytes_copied = ((char __user *)to) - optval;
+       if (put_user(bytes_copied, optlen))
+               return -EFAULT;
+
+unlock:
+       sctp_read_unlock(addr_lock);
+       return err;
 }
 
 /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR)
@@ -3021,11 +4167,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
  * association peer's addresses.
  */
 static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
-                                       char *optval, int *optlen)
+                                       char __user *optval, int __user *optlen)
 {
        struct sctp_prim prim;
        struct sctp_association *asoc;
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
 
        if (len != sizeof(struct sctp_prim))
                return -EINVAL;
@@ -3056,6 +4202,27 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
        return 0;
 }
 
+/*
+ * 7.1.11  Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER)
+ *
+ * Requests that the local endpoint set the specified Adaption Layer
+ * Indication parameter for all future INIT and INIT-ACK exchanges.
+ */
+static int sctp_getsockopt_adaption_layer(struct sock *sk, int len,
+                                 char __user *optval, int __user *optlen)
+{
+       struct sctp_setadaption adaption;
+
+       if (len != sizeof(struct sctp_setadaption))
+               return -EINVAL;
+
+       adaption.ssb_adaption_ind = sctp_sk(sk)->adaption_ind;
+       if (copy_to_user(optval, &adaption, len))
+               return -EFAULT;
+
+       return 0;
+}
+
 /*
  *
  * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM)
@@ -3076,11 +4243,12 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
  *   For getsockopt, it get the default sctp_sndrcvinfo structure.
  */
 static int sctp_getsockopt_default_send_param(struct sock *sk,
-                                       int len, char *optval, int *optlen)
+                                       int len, char __user *optval,
+                                       int __user *optlen)
 {
        struct sctp_sndrcvinfo info;
        struct sctp_association *asoc;
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
 
        if (len != sizeof(struct sctp_sndrcvinfo))
                return -EINVAL;
@@ -3122,7 +4290,7 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
  */
 
 static int sctp_getsockopt_nodelay(struct sock *sk, int len,
-                                  char *optval, int *optlen)
+                                  char __user *optval, int __user *optlen)
 {
        int val;
 
@@ -3150,8 +4318,9 @@ static int sctp_getsockopt_nodelay(struct sock *sk, int len,
  * be changed.
  *
  */
-static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval,
-                               int *optlen) {
+static int sctp_getsockopt_rtoinfo(struct sock *sk, int len,
+                               char __user *optval,
+                               int __user *optlen) {
        struct sctp_rtoinfo rtoinfo;
        struct sctp_association *asoc;
 
@@ -3168,12 +4337,12 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval,
 
        /* Values corresponding to the specific association. */
        if (asoc) {
-               rtoinfo.srto_initial = JIFFIES_TO_MSECS(asoc->rto_initial);
-               rtoinfo.srto_max = JIFFIES_TO_MSECS(asoc->rto_max);
-               rtoinfo.srto_min = JIFFIES_TO_MSECS(asoc->rto_min);
+               rtoinfo.srto_initial = jiffies_to_msecs(asoc->rto_initial);
+               rtoinfo.srto_max = jiffies_to_msecs(asoc->rto_max);
+               rtoinfo.srto_min = jiffies_to_msecs(asoc->rto_min);
        } else {
                /* Values corresponding to the endpoint. */
-               struct sctp_opt *sp = sctp_sk(sk);
+               struct sctp_sock *sp = sctp_sk(sk);
 
                rtoinfo.srto_initial = sp->rtoinfo.srto_initial;
                rtoinfo.srto_max = sp->rtoinfo.srto_max;
@@ -3200,8 +4369,9 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval,
  * See [SCTP] for more information.
  *
  */
-static int sctp_getsockopt_associnfo(struct sock *sk, int len, char *optval,
-                                    int *optlen)
+static int sctp_getsockopt_associnfo(struct sock *sk, int len,
+                                    char __user *optval,
+                                    int __user *optlen)
 {
 
        struct sctp_assocparams assocparams;
@@ -3222,7 +4392,7 @@ static int sctp_getsockopt_associnfo(struct sock *sk, int len, char *optval,
                return -EINVAL;
 
        /* Values correspoinding to the specific association */
-       if (assocparams.sasoc_assoc_id != 0) {
+       if (asoc) {
                assocparams.sasoc_asocmaxrxt = asoc->max_retrans;
                assocparams.sasoc_peer_rwnd = asoc->peer.rwnd;
                assocparams.sasoc_local_rwnd = asoc->a_rwnd;
@@ -3238,7 +4408,7 @@ static int sctp_getsockopt_associnfo(struct sock *sk, int len, char *optval,
                assocparams.sasoc_number_peer_destinations = cnt;
        } else {
                /* Values corresponding to the endpoint */
-               struct sctp_opt *sp = sctp_sk(sk);
+               struct sctp_sock *sp = sctp_sk(sk);
 
                assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt;
                assocparams.sasoc_peer_rwnd = sp->assocparams.sasoc_peer_rwnd;
@@ -3270,10 +4440,10 @@ static int sctp_getsockopt_associnfo(struct sock *sk, int len, char *optval,
  * addresses on the socket.
  */
 static int sctp_getsockopt_mappedv4(struct sock *sk, int len,
-                                   char *optval, int *optlen)
+                                   char __user *optval, int __user *optlen)
 {
        int val;
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
 
        if (len < sizeof(int))
                return -EINVAL;
@@ -3299,7 +4469,7 @@ static int sctp_getsockopt_mappedv4(struct sock *sk, int len,
  * the user.
  */
 static int sctp_getsockopt_maxseg(struct sock *sk, int len,
-                                 char *optval, int *optlen)
+                                 char __user *optval, int __user *optlen)
 {
        int val;
 
@@ -3318,12 +4488,13 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len,
 }
 
 SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
-                               char *optval, int *optlen)
+                               char __user *optval, int __user *optlen)
 {
        int retval = 0;
        int len;
 
-       SCTP_DEBUG_PRINTK("sctp_getsockopt(sk: %p, ...)\n", sk);
+       SCTP_DEBUG_PRINTK("sctp_getsockopt(sk: %p... optname: %d)\n",
+                         sk, optname);
 
        /* I can hardly begin to describe how wrong this is.  This is
         * so broken as to be worse than useless.  The API draft
@@ -3364,15 +4535,27 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
                                                          optlen);
                break;
+       case SCTP_DELAYED_ACK_TIME:
+               retval = sctp_getsockopt_delayed_ack_time(sk, len, optval,
+                                                         optlen);
+               break;
        case SCTP_INITMSG:
                retval = sctp_getsockopt_initmsg(sk, len, optval, optlen);
                break;
-       case SCTP_GET_PEER_ADDRS_NUM:
-               retval = sctp_getsockopt_peer_addrs_num(sk, len, optval,
+       case SCTP_GET_PEER_ADDRS_NUM_OLD:
+               retval = sctp_getsockopt_peer_addrs_num_old(sk, len, optval,
+                                                           optlen);
+               break;
+       case SCTP_GET_LOCAL_ADDRS_NUM_OLD:
+               retval = sctp_getsockopt_local_addrs_num_old(sk, len, optval,
+                                                            optlen);
+               break;
+       case SCTP_GET_PEER_ADDRS_OLD:
+               retval = sctp_getsockopt_peer_addrs_old(sk, len, optval,
                                                        optlen);
                break;
-       case SCTP_GET_LOCAL_ADDRS_NUM:
-               retval = sctp_getsockopt_local_addrs_num(sk, len, optval,
+       case SCTP_GET_LOCAL_ADDRS_OLD:
+               retval = sctp_getsockopt_local_addrs_old(sk, len, optval,
                                                         optlen);
                break;
        case SCTP_GET_PEER_ADDRS:
@@ -3409,6 +4592,10 @@ 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,
+                                                       optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -3621,7 +4808,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
  */
 SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
 {
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
        struct sctp_endpoint *ep = sp->ep;
 
        /* Only UDP style sockets that are not peeled off are allowed to
@@ -3670,7 +4857,7 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
  */
 SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
 {
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
        struct sctp_endpoint *ep = sp->ep;
 
        /* If backlog is zero, disable listening. */
@@ -3750,8 +4937,7 @@ out:
        sctp_release_sock(sk);
        return err;
 cleanup:
-       if (tfm)
-               sctp_crypto_free_tfm(tfm);
+       sctp_crypto_free_tfm(tfm);
        goto out;
 }
 
@@ -3760,7 +4946,7 @@ cleanup:
  * tcp_poll().  Note that, based on these implementations, we don't
  * lock the socket in this function, even though it seems that,
  * ideally, locking or some other mechanisms can be used to ensure
- * the integrity of the counters (sndbuf and wmem_queued) used
+ * the integrity of the counters (sndbuf and wmem_alloc) used
  * in this place.  We assume that we don't need locks either until proven
  * otherwise.
  *
@@ -3771,7 +4957,7 @@ cleanup:
 unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
 {
        struct sock *sk = sock->sk;
-       struct sctp_opt *sp = sctp_sk(sk);
+       struct sctp_sock *sp = sctp_sk(sk);
        unsigned int mask;
 
        poll_wait(file, sk->sk_sleep, wait);
@@ -3788,6 +4974,8 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
        /* Is there any exceptional events?  */
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP;
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
@@ -3845,7 +5033,7 @@ static struct sctp_bind_bucket *sctp_bucket_create(
 /* Caller must hold hashbucket lock for this tb with local BH disabled */
 static void sctp_bucket_destroy(struct sctp_bind_bucket *pp)
 {
-       if (hlist_empty(&pp->owner)) {
+       if (pp && hlist_empty(&pp->owner)) {
                if (pp->next)
                        pp->next->pprev = pp->pprev;
                *(pp->pprev) = pp->next;
@@ -3945,12 +5133,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
        for (cmsg = CMSG_FIRSTHDR(msg);
             cmsg != NULL;
             cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) {
-               /* Check for minimum length.  The SCM code has this check.  */
-               if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
-                   (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
-                                   + cmsg->cmsg_len) > msg->msg_controllen) {
+               if (!CMSG_OK(msg, cmsg))
                        return -EINVAL;
-               }
 
                /* Should we parse this header or ignore?  */
                if (cmsg->cmsg_level != IPPROTO_SCTP)
@@ -3999,8 +5183,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
 
                        /* Minimally, validate the sinfo_flags. */
                        if (cmsgs->info->sinfo_flags &
-                           ~(MSG_UNORDERED | MSG_ADDR_OVER |
-                             MSG_ABORT | MSG_EOF))
+                           ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
+                             SCTP_ABORT | SCTP_EOF))
                                return -EINVAL;
                        break;
 
@@ -4081,11 +5265,6 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
        struct sk_buff *skb;
        long timeo;
 
-       /* Caller is allowed not to check sk->sk_err before calling.  */
-       error = sock_error(sk);
-       if (error)
-               goto no_packet;
-
        timeo = sock_rcvtimeo(sk, noblock);
 
        SCTP_DEBUG_PRINTK("Timeout: timeo: %ld, MAX: %ld.\n",
@@ -4100,15 +5279,11 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
                 *  However, this function was corrent in any case. 8)
                 */
                if (flags & MSG_PEEK) {
-                       unsigned long cpu_flags;
-
-                       sctp_spin_lock_irqsave(&sk->sk_receive_queue.lock,
-                                              cpu_flags);
+                       spin_lock_bh(&sk->sk_receive_queue.lock);
                        skb = skb_peek(&sk->sk_receive_queue);
                        if (skb)
                                atomic_inc(&skb->users);
-                       sctp_spin_unlock_irqrestore(&sk->sk_receive_queue.lock,
-                                                   cpu_flags);
+                       spin_unlock_bh(&sk->sk_receive_queue.lock);
                } else {
                        skb = skb_dequeue(&sk->sk_receive_queue);
                }
@@ -4116,6 +5291,11 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
                if (skb)
                        return skb;
 
+               /* Caller is allowed not to check sk->sk_err before calling. */
+               error = sock_error(sk);
+               if (error)
+                       goto no_packet;
+
                if (sk->sk_shutdown & RCV_SHUTDOWN)
                        break;
 
@@ -4132,64 +5312,6 @@ no_packet:
        return NULL;
 }
 
-/* Verify that this is a valid address. */
-static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
-                                  int len)
-{
-       struct sctp_af *af;
-
-       /* Verify basic sockaddr. */
-       af = sctp_sockaddr_af(sctp_sk(sk), addr, len);
-       if (!af)
-               return -EINVAL;
-
-       /* Is this a valid SCTP address?  */
-       if (!af->addr_valid(addr, sctp_sk(sk)))
-               return -EINVAL;
-
-       if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr)))
-               return -EINVAL;
-
-       return 0;
-}
-
-/* Get the sndbuf space available at the time on the association.  */
-static inline int sctp_wspace(struct sctp_association *asoc)
-{
-       struct sock *sk = asoc->base.sk;
-       int amt = 0;
-
-       amt = sk->sk_sndbuf - asoc->sndbuf_used;
-       if (amt < 0)
-               amt = 0;
-       return amt;
-}
-
-/* Increment the used sndbuf space count of the corresponding association by
- * the size of the outgoing data chunk.
- * Also, set the skb destructor for sndbuf accounting later.
- *
- * Since it is always 1-1 between chunk and skb, and also a new skb is always
- * allocated for chunk bundling in sctp_packet_transmit(), we can use the
- * destructor in the data chunk skb for the purpose of the sndbuf space
- * tracking.
- */
-static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
-{
-       struct sctp_association *asoc = chunk->asoc;
-       struct sock *sk = asoc->base.sk;
-
-       /* The sndbuf space is tracked per association.  */
-       sctp_association_hold(asoc);
-
-       chunk->skb->destructor = sctp_wfree;
-       /* Save the chunk pointer in skb for sctp_wfree to use later.  */
-       *((struct sctp_chunk **)(chunk->skb->cb)) = chunk;
-
-       asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk);
-       sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk);
-}
-
 /* If sndbuf has changed, wake up per association sndbuf waiters.  */
 static void __sctp_write_space(struct sctp_association *asoc)
 {
@@ -4229,8 +5351,13 @@ static void sctp_wfree(struct sk_buff *skb)
        chunk = *((struct sctp_chunk **)(skb->cb));
        asoc = chunk->asoc;
        sk = asoc->base.sk;
-       asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk);
-       sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk);
+       asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) +
+                               sizeof(struct sk_buff) +
+                               sizeof(struct sctp_chunk);
+
+       atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
+
+       sock_wfree(skb);
        __sctp_write_space(asoc);
 
        sctp_association_put(asoc);
@@ -4270,6 +5397,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;
@@ -4311,7 +5439,7 @@ void sctp_write_space(struct sock *sk)
 
 /* Is there any sndbuf space available on the socket?
  *
- * Note that wmem_queued is the sum of the send buffers on all of the
+ * Note that sk_wmem_alloc is the sum of the send buffers on all of the
  * associations on the same socket.  For a UDP-style socket with
  * multiple associations, it is possible for it to be "unwriteable"
  * prematurely.  I assume that this is acceptable because
@@ -4324,7 +5452,7 @@ static int sctp_writeable(struct sock *sk)
 {
        int amt = 0;
 
-       amt = sk->sk_sndbuf - sk->sk_wmem_queued;
+       amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
        if (amt < 0)
                amt = 0;
        return amt;
@@ -4381,7 +5509,10 @@ out:
        return err;
 
 do_error:
-       err = -ECONNREFUSED;
+       if (asoc->init_err_counter + 1 > asoc->max_init_attempts)
+               err = -ETIMEDOUT;
+       else
+               err = -ECONNREFUSED;
        goto out;
 
 do_interrupted:
@@ -4457,12 +5588,13 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
                              struct sctp_association *assoc,
                              sctp_socket_type_t type)
 {
-       struct sctp_opt *oldsp = sctp_sk(oldsk);
-       struct sctp_opt *newsp = sctp_sk(newsk);
+       struct sctp_sock *oldsp = sctp_sk(oldsk);
+       struct sctp_sock *newsp = sctp_sk(newsk);
        struct sctp_bind_bucket *pp; /* hash list port iterator */
        struct sctp_endpoint *newep = newsp->ep;
        struct sk_buff *skb, *tmp;
        struct sctp_ulpevent *event;
+       int flags = 0;
 
        /* Migrate socket buffer sizes and all the socket level options to the
         * new socket.
@@ -4470,7 +5602,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
        newsk->sk_sndbuf = oldsk->sk_sndbuf;
        newsk->sk_rcvbuf = oldsk->sk_rcvbuf;
        /* Brute force copy old sctp opt. */
-       memcpy(newsp, oldsp, sizeof(struct sctp_opt));
+       inet_sk_copy_descendant(newsk, oldsk);
 
        /* Restore the ep value that was overwritten with the above structure
         * copy.
@@ -4484,14 +5616,27 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
        sctp_sk(newsk)->bind_hash = pp;
        inet_sk(newsk)->num = inet_sk(oldsk)->num;
 
+       /* Copy the bind_addr list from the original endpoint to the new
+        * endpoint so that we can handle restarts properly
+        */
+       if (assoc->peer.ipv4_address)
+               flags |= SCTP_ADDR4_PEERSUPP;
+       if (assoc->peer.ipv6_address)
+               flags |= SCTP_ADDR6_PEERSUPP;
+       sctp_bind_addr_copy(&newsp->ep->base.bind_addr,
+                            &oldsp->ep->base.bind_addr,
+                            SCTP_SCOPE_GLOBAL, GFP_KERNEL, flags);
+
        /* Move any messages in the old socket's receive queue that are for the
         * peeled off association to the new socket's receive queue.
         */
        sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
                event = sctp_skb2event(skb);
                if (event->asoc == assoc) {
-                       __skb_unlink(skb, skb->list);
+                       sock_rfree(skb);
+                       __skb_unlink(skb, &oldsk->sk_receive_queue);
                        __skb_queue_tail(&newsk->sk_receive_queue, skb);
+                       skb_set_owner_r(skb, newsk);
                }
        }
 
@@ -4499,7 +5644,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
         * delivery.   Three cases:
         * 1) No partial deliver;  no work.
         * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
-        * 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue.
+        * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue.
         */
        skb_queue_head_init(&newsp->pd_lobby);
        sctp_sk(newsk)->pd_mode = assoc->ulpq.pd_mode;
@@ -4519,8 +5664,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
                sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
                        event = sctp_skb2event(skb);
                        if (event->asoc == assoc) {
-                               __skb_unlink(skb, skb->list);
+                               sock_rfree(skb);
+                               __skb_unlink(skb, &oldsp->pd_lobby);
                                __skb_queue_tail(queue, skb);
+                               skb_set_owner_r(skb, newsk);
                        }
                }
 
@@ -4538,7 +5685,13 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
         */
        newsp->type = type;
 
-       /* 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);
 
        /* If the association on the newsk is already closed before accept()
@@ -4548,11 +5701,13 @@ 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.  */
 struct proto sctp_prot = {
        .name        =  "SCTP",
+       .owner       =  THIS_MODULE,
        .close       =  sctp_close,
        .connect     =  sctp_connect,
        .disconnect  =  sctp_disconnect,
@@ -4570,4 +5725,30 @@ struct proto sctp_prot = {
        .hash        =  sctp_hash,
        .unhash      =  sctp_unhash,
        .get_port    =  sctp_get_port,
+       .obj_size    =  sizeof(struct sctp_sock),
+};
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+struct proto sctpv6_prot = {
+       .name           = "SCTPv6",
+       .owner          = THIS_MODULE,
+       .close          = sctp_close,
+       .connect        = sctp_connect,
+       .disconnect     = sctp_disconnect,
+       .accept         = sctp_accept,
+       .ioctl          = sctp_ioctl,
+       .init           = sctp_init_sock,
+       .destroy        = sctp_destroy_sock,
+       .shutdown       = sctp_shutdown,
+       .setsockopt     = sctp_setsockopt,
+       .getsockopt     = sctp_getsockopt,
+       .sendmsg        = sctp_sendmsg,
+       .recvmsg        = sctp_recvmsg,
+       .bind           = sctp_bind,
+       .backlog_rcv    = sctp_backlog_rcv,
+       .hash           = sctp_hash,
+       .unhash         = sctp_unhash,
+       .get_port       = sctp_get_port,
+       .obj_size       = sizeof(struct sctp6_sock),
 };
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */