mmc: s3c6410: enable ADMA feature in 6410 sdhci controller
[safe/jmp/linux-2.6] / net / sctp / socket.c
index 7cd58ef..ca44917 100644 (file)
@@ -1,4 +1,4 @@
-/* SCTP kernel reference Implementation
+/* SCTP kernel implementation
  * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
@@ -6,7 +6,7 @@
  * Copyright (c) 2001-2002 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
  *
- * This file is part of the SCTP kernel reference Implementation
+ * This file is part of the SCTP kernel implementation
  *
  * These functions interface with the sockets layer to implement the
  * SCTP Extensions for the Sockets API.
  * functions--this file is the functions which populate the struct proto
  * for SCTP which is the BOTTOM of the sockets interface.
  *
- * The SCTP reference implementation is free software;
+ * This SCTP implementation is free software;
  * you can redistribute it and/or modify it under the terms of
  * the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * any later version.
  *
- * The SCTP reference implementation is distributed in the hope that it
+ * This SCTP implementation is distributed in the hope that it
  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  *                 ************************
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
@@ -67,6 +67,7 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/crypto.h>
+#include <linux/slab.h>
 
 #include <net/ip.h>
 #include <net/icmp.h>
@@ -114,9 +115,9 @@ extern int sysctl_sctp_wmem[3];
 
 static int sctp_memory_pressure;
 static atomic_t sctp_memory_allocated;
-static atomic_t sctp_sockets_allocated;
+struct percpu_counter sctp_sockets_allocated;
 
-static void sctp_enter_memory_pressure(void)
+static void sctp_enter_memory_pressure(struct sock *sk)
 {
        sctp_memory_pressure = 1;
 }
@@ -130,7 +131,7 @@ static inline int sctp_wspace(struct sctp_association *asoc)
        if (asoc->ep->sndbuf_policy)
                amt = asoc->sndbuf_used;
        else
-               amt = atomic_read(&asoc->base.sk->sk_wmem_alloc);
+               amt = sk_wmem_alloc_get(asoc->base.sk);
 
        if (amt >= asoc->base.sk->sk_sndbuf) {
                if (asoc->base.sk->sk_userlocks & SOCK_SNDBUF_LOCK)
@@ -174,7 +175,8 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
                                sizeof(struct sctp_chunk);
 
        atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
-       sk_charge_skb(sk, chunk->skb);
+       sk->sk_wmem_queued += chunk->skb->truesize;
+       sk_mem_charge(sk, chunk->skb->truesize);
 }
 
 /* Verify that this is a valid address. */
@@ -307,9 +309,16 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
        if (len < sizeof (struct sockaddr))
                return NULL;
 
-       /* Does this PF support this AF? */
-       if (!opt->pf->af_supported(addr->sa.sa_family, opt))
-               return NULL;
+       /* V4 mapped address are really of AF_INET family */
+       if (addr->sa.sa_family == AF_INET6 &&
+           ipv6_addr_v4mapped(&addr->v6.sin6_addr)) {
+               if (!opt->pf->af_supported(AF_INET, opt))
+                       return NULL;
+       } else {
+               /* Does this PF support this AF? */
+               if (!opt->pf->af_supported(addr->sa.sa_family, opt))
+                       return NULL;
+       }
 
        /* If we get this far, af is valid. */
        af = sctp_get_af_specific(addr->sa.sa_family);
@@ -369,32 +378,33 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
        if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
                return -EACCES;
 
+       /* See if the address matches any of the addresses we may have
+        * already bound before checking against other endpoints.
+        */
+       if (sctp_bind_addr_match(bp, addr, sp))
+               return -EINVAL;
+
        /* Make sure we are allowed to bind here.
         * The function sctp_get_port_local() does duplicate address
         * detection.
         */
        addr->v4.sin_port = htons(snum);
        if ((ret = sctp_get_port_local(sk, addr))) {
-               if (ret == (long) sk) {
-                       /* This endpoint has a conflicting address. */
-                       return -EINVAL;
-               } else {
-                       return -EADDRINUSE;
-               }
+               return -EADDRINUSE;
        }
 
        /* Refresh ephemeral port.  */
        if (!bp->port)
-               bp->port = inet_sk(sk)->num;
+               bp->port = inet_sk(sk)->inet_num;
 
        /* Add the address to the bind address list.
         * Use GFP_ATOMIC since BHs will be disabled.
         */
-       ret = sctp_add_bind_addr(bp, addr, 1, GFP_ATOMIC);
+       ret = sctp_add_bind_addr(bp, addr, SCTP_ADDR_SRC, GFP_ATOMIC);
 
        /* Copy back into socket for getsockname() use. */
        if (!ret) {
-               inet_sk(sk)->sport = htons(inet_sk(sk)->num);
+               inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num);
                af->to_sk_saddr(addr, sk);
        }
 
@@ -512,7 +522,6 @@ static int sctp_send_asconf_add_ip(struct sock              *sk,
        union sctp_addr                 saveaddr;
        void                            *addr_buf;
        struct sctp_af                  *af;
-       struct list_head                *pos;
        struct list_head                *p;
        int                             i;
        int                             retval = 0;
@@ -524,10 +533,9 @@ static int sctp_send_asconf_add_ip(struct sock             *sk,
        ep = sp->ep;
 
        SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
-                         __FUNCTION__, sk, addrs, addrcnt);
+                         __func__, sk, addrs, addrcnt);
 
-       list_for_each(pos, &ep->asocs) {
-               asoc = list_entry(pos, struct sctp_association, asocs);
+       list_for_each_entry(asoc, &ep->asocs, asocs) {
 
                if (!asoc->peer.asconf_capable)
                        continue;
@@ -585,8 +593,8 @@ static int sctp_send_asconf_add_ip(struct sock              *sk,
                        addr = (union sctp_addr *)addr_buf;
                        af = sctp_get_af_specific(addr->v4.sin_family);
                        memcpy(&saveaddr, addr, af->sockaddr_len);
-                       retval = sctp_add_bind_addr(bp, &saveaddr, 0,
-                                                   GFP_ATOMIC);
+                       retval = sctp_add_bind_addr(bp, &saveaddr,
+                                                   SCTP_ADDR_NEW, GFP_ATOMIC);
                        addr_buf += af->sockaddr_len;
                }
        }
@@ -660,7 +668,7 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
                 * socket routing and failover schemes. Refer to comments in
                 * sctp_do_bind(). -daisy
                 */
-               retval = sctp_del_bind_addr(bp, sa_addr, call_rcu);
+               retval = sctp_del_bind_addr(bp, sa_addr);
 
                addr_buf += af->sockaddr_len;
 err_bindx_rem:
@@ -698,7 +706,6 @@ static int sctp_send_asconf_del_ip(struct sock              *sk,
        union sctp_addr         *laddr;
        void                    *addr_buf;
        struct sctp_af          *af;
-       struct list_head        *pos, *pos1;
        struct sctp_sockaddr_entry *saddr;
        int                     i;
        int                     retval = 0;
@@ -710,10 +717,9 @@ static int sctp_send_asconf_del_ip(struct sock             *sk,
        ep = sp->ep;
 
        SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
-                         __FUNCTION__, sk, addrs, addrcnt);
+                         __func__, sk, addrs, addrcnt);
 
-       list_for_each(pos, &ep->asocs) {
-               asoc = list_entry(pos, struct sctp_association, asocs);
+       list_for_each_entry(asoc, &ep->asocs, asocs) {
 
                if (!asoc->peer.asconf_capable)
                        continue;
@@ -777,7 +783,7 @@ static int sctp_send_asconf_del_ip(struct sock              *sk,
                        af = sctp_get_af_specific(laddr->v4.sin_family);
                        list_for_each_entry(saddr, &bp->address_list, list) {
                                if (sctp_cmp_addr_exact(&saddr->a, laddr))
-                                       saddr->use_as_src = 0;
+                                       saddr->state = SCTP_ADDR_DEL;
                        }
                        addr_buf += af->sockaddr_len;
                }
@@ -786,9 +792,8 @@ static int sctp_send_asconf_del_ip(struct sock              *sk,
                 * 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);
+               list_for_each_entry(transport, &asoc->peer.transport_addr_list,
+                                       transports) {
                        dst_release(transport->dst);
                        sctp_transport_route(transport, NULL,
                                             sctp_sk(asoc->base.sk));
@@ -960,7 +965,8 @@ out:
  */
 static int __sctp_connect(struct sock* sk,
                          struct sockaddr *kaddrs,
-                         int addrs_size)
+                         int addrs_size,
+                         sctp_assoc_t *assoc_id)
 {
        struct sctp_sock *sp;
        struct sctp_endpoint *ep;
@@ -1075,6 +1081,13 @@ static int __sctp_connect(struct sock* sk,
                                err = -ENOMEM;
                                goto out_free;
                        }
+
+                       err = sctp_assoc_set_bind_addr_from_ep(asoc, scope,
+                                                             GFP_KERNEL);
+                       if (err < 0) {
+                               goto out_free;
+                       }
+
                }
 
                /* Prime the peer's transport structures.  */
@@ -1090,9 +1103,13 @@ static int __sctp_connect(struct sock* sk,
                walk_size += af->sockaddr_len;
        }
 
-       err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL);
-       if (err < 0) {
-               goto out_free;
+       /* In case the user of sctp_connectx() wants an association
+        * id back, assign one now.
+        */
+       if (assoc_id) {
+               err = sctp_assoc_set_id(asoc, GFP_KERNEL);
+               if (err < 0)
+                       goto out_free;
        }
 
        err = sctp_primitive_ASSOCIATE(asoc, NULL);
@@ -1101,7 +1118,7 @@ static int __sctp_connect(struct sock* sk,
        }
 
        /* Initialize sk's dport and daddr for getpeername() */
-       inet_sk(sk)->dport = htons(asoc->peer.port);
+       inet_sk(sk)->inet_dport = htons(asoc->peer.port);
        af = sctp_get_af_specific(sa_addr->sa.sa_family);
        af->to_sk_daddr(sa_addr, sk);
        sk->sk_err = 0;
@@ -1115,6 +1132,8 @@ static int __sctp_connect(struct sock* sk,
        timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);
 
        err = sctp_wait_for_connect(asoc, &timeo);
+       if ((err == 0 || err == -EINPROGRESS) && assoc_id)
+               *assoc_id = asoc->assoc_id;
 
        /* Don't free association on exit. */
        asoc = NULL;
@@ -1132,7 +1151,8 @@ out_free:
 /* Helper for tunneling sctp_connectx() requests through sctp_setsockopt()
  *
  * API 8.9
- * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt);
+ * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt,
+ *                     sctp_assoc_t *asoc);
  *
  * 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
@@ -1148,8 +1168,10 @@ out_free:
  * 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.
+ * On success, sctp_connectx() returns 0. It also sets the assoc_id to
+ * the association id of the new association.  On failure, sctp_connectx()
+ * returns -1, and sets errno to the appropriate error code.  The assoc_id
+ * is not touched by the kernel.
  *
  * For SCTP, the port given in each socket address must be the same, or
  * sctp_connectx() will fail, setting errno to EINVAL.
@@ -1186,17 +1208,18 @@ out_free:
  * addrs     The pointer to the addresses in user land
  * addrssize Size of the addrs buffer
  *
- * Returns 0 if ok, <0 errno code on error.
+ * Returns >=0 if ok, <0 errno code on error.
  */
-SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
+SCTP_STATIC int __sctp_setsockopt_connectx(struct sock* sk,
                                      struct sockaddr __user *addrs,
-                                     int addrs_size)
+                                     int addrs_size,
+                                     sctp_assoc_t *assoc_id)
 {
        int err = 0;
        struct sockaddr *kaddrs;
 
        SCTP_DEBUG_PRINTK("%s - sk %p addrs %p addrs_size %d\n",
-                         __FUNCTION__, sk, addrs, addrs_size);
+                         __func__, sk, addrs, addrs_size);
 
        if (unlikely(addrs_size <= 0))
                return -EINVAL;
@@ -1213,10 +1236,79 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
        if (__copy_from_user(kaddrs, addrs, addrs_size)) {
                err = -EFAULT;
        } else {
-               err = __sctp_connect(sk, kaddrs, addrs_size);
+               err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
        }
 
        kfree(kaddrs);
+
+       return err;
+}
+
+/*
+ * This is an older interface.  It's kept for backward compatibility
+ * to the option that doesn't provide association id.
+ */
+SCTP_STATIC int sctp_setsockopt_connectx_old(struct sock* sk,
+                                     struct sockaddr __user *addrs,
+                                     int addrs_size)
+{
+       return __sctp_setsockopt_connectx(sk, addrs, addrs_size, NULL);
+}
+
+/*
+ * New interface for the API.  The since the API is done with a socket
+ * option, to make it simple we feed back the association id is as a return
+ * indication to the call.  Error is always negative and association id is
+ * always positive.
+ */
+SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
+                                     struct sockaddr __user *addrs,
+                                     int addrs_size)
+{
+       sctp_assoc_t assoc_id = 0;
+       int err = 0;
+
+       err = __sctp_setsockopt_connectx(sk, addrs, addrs_size, &assoc_id);
+
+       if (err)
+               return err;
+       else
+               return assoc_id;
+}
+
+/*
+ * New (hopefully final) interface for the API.
+ * We use the sctp_getaddrs_old structure so that use-space library
+ * can avoid any unnecessary allocations.   The only defferent part
+ * is that we store the actual length of the address buffer into the
+ * addrs_num structure member.  That way we can re-use the existing
+ * code.
+ */
+SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len,
+                                       char __user *optval,
+                                       int __user *optlen)
+{
+       struct sctp_getaddrs_old param;
+       sctp_assoc_t assoc_id = 0;
+       int err = 0;
+
+       if (len < sizeof(param))
+               return -EINVAL;
+
+       if (copy_from_user(&param, optval, sizeof(param)))
+               return -EFAULT;
+
+       err = __sctp_setsockopt_connectx(sk,
+                       (struct sockaddr __user *)param.addrs,
+                       param.addr_num, &assoc_id);
+
+       if (err == 0 || err == -EINPROGRESS) {
+               if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
+                       return -EFAULT;
+               if (put_user(sizeof(assoc_id), optlen))
+                       return -EFAULT;
+       }
+
        return err;
 }
 
@@ -1280,6 +1372,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
 
        sctp_lock_sock(sk);
        sk->sk_shutdown = SHUTDOWN_MASK;
+       sk->sk_state = SCTP_SS_CLOSING;
 
        ep = sctp_sk(sk)->ep;
 
@@ -1396,7 +1489,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        long timeo;
        __u16 sinfo_flags = 0;
        struct sctp_datamsg *datamsg;
-       struct list_head *pos;
        int msg_flags = msg->msg_flags;
 
        SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %zu)\n",
@@ -1608,6 +1700,11 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                        goto out_unlock;
                }
                asoc = new_asoc;
+               err = sctp_assoc_set_bind_addr_from_ep(asoc, scope, GFP_KERNEL);
+               if (err < 0) {
+                       err = -ENOMEM;
+                       goto out_free;
+               }
 
                /* If the SCTP_INIT ancillary data is specified, set all
                 * the association init values accordingly.
@@ -1637,11 +1734,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                        err = -ENOMEM;
                        goto out_free;
                }
-               err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL);
-               if (err < 0) {
-                       err = -ENOMEM;
-                       goto out_free;
-               }
        }
 
        /* ASSERT: we have a valid association at this point.  */
@@ -1726,28 +1818,29 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        }
 
        /* Now send the (possibly) fragmented message. */
-       list_for_each(pos, &datamsg->chunks) {
-               chunk = list_entry(pos, struct sctp_chunk, frag_list);
-               sctp_datamsg_track(chunk);
+       list_for_each_entry(chunk, &datamsg->chunks, frag_list) {
+               sctp_chunk_hold(chunk);
 
                /* Do accounting for the write space.  */
                sctp_set_owner_w(chunk);
 
                chunk->transport = chunk_tp;
-
-               /* Send it to the lower layers.  Note:  all chunks
-                * must either fail or succeed.   The lower layer
-                * works that way today.  Keep it that way or this
-                * breaks.
-                */
-               err = sctp_primitive_SEND(asoc, chunk);
-               /* Did the lower layer accept the chunk? */
-               if (err)
-                       sctp_chunk_free(chunk);
-               SCTP_DEBUG_PRINTK("We sent primitively.\n");
        }
 
-       sctp_datamsg_free(datamsg);
+       /* Send it to the lower layers.  Note:  all chunks
+        * must either fail or succeed.   The lower layer
+        * works that way today.  Keep it that way or this
+        * breaks.
+        */
+       err = sctp_primitive_SEND(asoc, datamsg);
+       /* Did the lower layer accept the chunk? */
+       if (err)
+               sctp_datamsg_free(datamsg);
+       else
+               sctp_datamsg_put(datamsg);
+
+       SCTP_DEBUG_PRINTK("We sent primitively.\n");
+
        if (err)
                goto out_free;
        else
@@ -1802,7 +1895,7 @@ static int sctp_skb_pull(struct sk_buff *skb, int len)
        len -= skb_len;
        __skb_pull(skb, skb_len);
 
-       for (list = skb_shinfo(skb)->frag_list; list; list = list->next) {
+       skb_walk_frags(skb, list) {
                rlen = sctp_skb_pull(list, len);
                skb->len -= (len-rlen);
                skb->data_len -= (len-rlen);
@@ -1876,7 +1969,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
        if (err)
                goto out_free;
 
-       sock_recv_timestamp(msg, sk, skb);
+       sock_recv_ts_and_drops(msg, sk, skb);
        if (sctp_ulpevent_is_notification(event)) {
                msg->msg_flags |= MSG_NOTIFICATION;
                sp->pf->event_msgname(event, msg->msg_name, addr_len);
@@ -1910,7 +2003,8 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
                 * rwnd by that amount. If all the data in the skb is read,
                 * rwnd is updated when the event is freed.
                 */
-               sctp_assoc_rwnd_increase(event->asoc, copied);
+               if (!sctp_ulpevent_is_notification(event))
+                       sctp_assoc_rwnd_increase(event->asoc, copied);
                goto out;
        } else if ((event->msg_flags & MSG_NOTIFICATION) ||
                   (event->msg_flags & MSG_EOR))
@@ -1944,7 +2038,8 @@ out:
  * instead a error will be indicated to the user.
  */
 static int sctp_setsockopt_disable_fragments(struct sock *sk,
-                                           char __user *optval, int optlen)
+                                            char __user *optval,
+                                            unsigned int optlen)
 {
        int val;
 
@@ -1960,9 +2055,9 @@ static int sctp_setsockopt_disable_fragments(struct sock *sk,
 }
 
 static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
-                                       int optlen)
+                                 unsigned int optlen)
 {
-       if (optlen != sizeof(struct sctp_event_subscribe))
+       if (optlen > sizeof(struct sctp_event_subscribe))
                return -EINVAL;
        if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen))
                return -EFAULT;
@@ -1981,7 +2076,7 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
  * association is closed.
  */
 static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
-                                           int optlen)
+                                    unsigned int optlen)
 {
        struct sctp_sock *sp = sctp_sk(sk);
 
@@ -1992,6 +2087,8 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
                return -EINVAL;
        if (copy_from_user(&sp->autoclose, optval, optlen))
                return -EFAULT;
+       /* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */
+       sp->autoclose = min_t(long, sp->autoclose, MAX_SCHEDULE_TIMEOUT / HZ);
 
        return 0;
 }
@@ -2160,7 +2257,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
                        sctp_assoc_sync_pmtu(asoc);
                } else if (asoc) {
                        asoc->pathmtu = params->spp_pathmtu;
-                       sctp_frag_point(sp, params->spp_pathmtu);
+                       sctp_frag_point(asoc, params->spp_pathmtu);
                } else {
                        sp->pathmtu = params->spp_pathmtu;
                }
@@ -2217,11 +2314,10 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
                }
        }
 
-       /* Note that unless the spp_flag is set to SPP_PMTUD_ENABLE the value
-        * of this field is ignored.  Note also that a value of zero
-        * indicates the current setting should be left unchanged.
+       /* Note that a value of zero indicates the current setting should be
+          left unchanged.
         */
-       if ((params->spp_flags & SPP_PMTUD_ENABLE) && params->spp_pathmaxrxt) {
+       if (params->spp_pathmaxrxt) {
                if (trans) {
                        trans->pathmaxrxt = params->spp_pathmaxrxt;
                } else if (asoc) {
@@ -2235,7 +2331,8 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
 }
 
 static int sctp_setsockopt_peer_addr_params(struct sock *sk,
-                                           char __user *optval, int optlen)
+                                           char __user *optval,
+                                           unsigned int optlen)
 {
        struct sctp_paddrparams  params;
        struct sctp_transport   *trans = NULL;
@@ -2259,14 +2356,14 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
            pmtud_change     == SPP_PMTUD ||
            sackdelay_change == SPP_SACKDELAY ||
            params.spp_sackdelay > 500 ||
-           (params.spp_pathmtu
-           && params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
+           (params.spp_pathmtu &&
+            params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
                return -EINVAL;
 
        /* 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)) {
+       if (!sctp_is_any(sk, ( union sctp_addr *)&params.spp_address)) {
                trans = sctp_addr_id2transport(sk, &params.spp_address,
                                               params.spp_assoc_id);
                if (!trans)
@@ -2299,11 +2396,8 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
         * transport.
         */
        if (!trans && asoc) {
-               struct list_head *pos;
-
-               list_for_each(pos, &asoc->peer.transport_addr_list) {
-                       trans = list_entry(pos, struct sctp_transport,
-                                          transports);
+               list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+                               transports) {
                        sctp_apply_peer_addr_params(&params, trans, asoc, sp,
                                                    hb_change, pmtud_change,
                                                    sackdelay_change);
@@ -2313,74 +2407,98 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
        return 0;
 }
 
-/* 7.1.23. 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;
- *   };
+/*
+ * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
+ *
+ * This option will effect the way delayed acks are performed.  This
+ * option allows you to get or set the delayed ack time, in
+ * milliseconds.  It also allows changing the delayed ack frequency.
+ * Changing the frequency to 1 disables the delayed sack algorithm.  If
+ * the assoc_id is 0, then this sets or gets the endpoints default
+ * values.  If the assoc_id field is non-zero, then the set or get
+ * effects the specified association for the one to many model (the
+ * assoc_id field is ignored by the one to one model).  Note that if
+ * sack_delay or sack_freq are 0 when setting this option, then the
+ * current values will remain unchanged.
+ *
+ * struct sctp_sack_info {
+ *     sctp_assoc_t            sack_assoc_id;
+ *     uint32_t                sack_delay;
+ *     uint32_t                sack_freq;
+ * };
  *
- *     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).
+ * sack_assoc_id -  This parameter, indicates which association the user
+ *    is performing 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.
+ * sack_delay -  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.
+ * sack_freq -  This parameter contains the number of packets that must
+ *    be received before a sack is sent without waiting for the delay
+ *    timer to expire.  The default value for this is 2, setting this
+ *    value to 1 will disable the delayed sack algorithm.
  */
 
-static int sctp_setsockopt_delayed_ack_time(struct sock *sk,
-                                           char __user *optval, int optlen)
+static int sctp_setsockopt_delayed_ack(struct sock *sk,
+                                      char __user *optval, unsigned int optlen)
 {
-       struct sctp_assoc_value  params;
+       struct sctp_sack_info    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 (optlen == sizeof(struct sctp_sack_info)) {
+               if (copy_from_user(&params, optval, optlen))
+                       return -EFAULT;
 
-       if (copy_from_user(&params, optval, optlen))
-               return -EFAULT;
+               if (params.sack_delay == 0 && params.sack_freq == 0)
+                       return 0;
+       } else if (optlen == sizeof(struct sctp_assoc_value)) {
+               printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
+                      "in delayed_ack socket option deprecated\n");
+               printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
+               if (copy_from_user(&params, optval, optlen))
+                       return -EFAULT;
+
+               if (params.sack_delay == 0)
+                       params.sack_freq = 1;
+               else
+                       params.sack_freq = 0;
+       } else
+               return - EINVAL;
 
        /* Validate value parameter. */
-       if (params.assoc_value > 500)
+       if (params.sack_delay > 500)
                return -EINVAL;
 
-       /* Get association, if assoc_id != 0 and the socket is a one
+       /* Get association, if sack_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))
+       asoc = sctp_id2assoc(sk, params.sack_assoc_id);
+       if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP))
                return -EINVAL;
 
-       if (params.assoc_value) {
+       if (params.sack_delay) {
                if (asoc) {
                        asoc->sackdelay =
-                               msecs_to_jiffies(params.assoc_value);
+                               msecs_to_jiffies(params.sack_delay);
                        asoc->param_flags =
                                (asoc->param_flags & ~SPP_SACKDELAY) |
                                SPP_SACKDELAY_ENABLE;
                } else {
-                       sp->sackdelay = params.assoc_value;
+                       sp->sackdelay = params.sack_delay;
                        sp->param_flags =
                                (sp->param_flags & ~SPP_SACKDELAY) |
                                SPP_SACKDELAY_ENABLE;
                }
-       } else {
+       }
+
+       if (params.sack_freq == 1) {
                if (asoc) {
                        asoc->param_flags =
                                (asoc->param_flags & ~SPP_SACKDELAY) |
@@ -2390,25 +2508,40 @@ static int sctp_setsockopt_delayed_ack_time(struct sock *sk,
                                (sp->param_flags & ~SPP_SACKDELAY) |
                                SPP_SACKDELAY_DISABLE;
                }
+       } else if (params.sack_freq > 1) {
+               if (asoc) {
+                       asoc->sackfreq = params.sack_freq;
+                       asoc->param_flags =
+                               (asoc->param_flags & ~SPP_SACKDELAY) |
+                               SPP_SACKDELAY_ENABLE;
+               } else {
+                       sp->sackfreq = params.sack_freq;
+                       sp->param_flags =
+                               (sp->param_flags & ~SPP_SACKDELAY) |
+                               SPP_SACKDELAY_ENABLE;
+               }
        }
 
        /* 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) {
+               list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+                               transports) {
+                       if (params.sack_delay) {
                                trans->sackdelay =
-                                       msecs_to_jiffies(params.assoc_value);
+                                       msecs_to_jiffies(params.sack_delay);
                                trans->param_flags =
                                        (trans->param_flags & ~SPP_SACKDELAY) |
                                        SPP_SACKDELAY_ENABLE;
-                       } else {
+                       }
+                       if (params.sack_freq == 1) {
                                trans->param_flags =
                                        (trans->param_flags & ~SPP_SACKDELAY) |
                                        SPP_SACKDELAY_DISABLE;
+                       } else if (params.sack_freq > 1) {
+                               trans->sackfreq = params.sack_freq;
+                               trans->param_flags =
+                                       (trans->param_flags & ~SPP_SACKDELAY) |
+                                       SPP_SACKDELAY_ENABLE;
                        }
                }
        }
@@ -2427,7 +2560,7 @@ static int sctp_setsockopt_delayed_ack_time(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 __user *optval, int optlen)
+static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigned int optlen)
 {
        struct sctp_initmsg sinit;
        struct sctp_sock *sp = sctp_sk(sk);
@@ -2464,7 +2597,8 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int opt
  *   to this call if the caller is using the UDP model.
  */
 static int sctp_setsockopt_default_send_param(struct sock *sk,
-                                               char __user *optval, int optlen)
+                                             char __user *optval,
+                                             unsigned int optlen)
 {
        struct sctp_sndrcvinfo info;
        struct sctp_association *asoc;
@@ -2503,7 +2637,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
  * association peer's addresses.
  */
 static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
-                                       int optlen)
+                                       unsigned int optlen)
 {
        struct sctp_prim prim;
        struct sctp_transport *trans;
@@ -2532,7 +2666,7 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
  *  integer boolean flag.
  */
 static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval,
-                                       int optlen)
+                                  unsigned int optlen)
 {
        int val;
 
@@ -2557,7 +2691,8 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval,
  * be changed.
  *
  */
-static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int optlen) {
+static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigned int optlen)
+{
        struct sctp_rtoinfo rtoinfo;
        struct sctp_association *asoc;
 
@@ -2609,7 +2744,7 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int opt
  * See [SCTP] for more information.
  *
  */
-static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int optlen)
+static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsigned int optlen)
 {
 
        struct sctp_assocparams assocparams;
@@ -2630,18 +2765,15 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int o
                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);
+                       list_for_each_entry(peer_addr, &asoc->peer.transport_addr_list,
+                                       transports) {
                                path_sum += peer_addr->pathmaxrxt;
                                paths++;
                        }
 
-                       /* Only validate asocmaxrxt if we have more then
+                       /* Only validate asocmaxrxt if we have more than
                         * one path/transport.  We do this because path
                         * retransmissions are only counted when we have more
                         * then one path.
@@ -2684,7 +2816,7 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int o
  * 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 __user *optval, int optlen)
+static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsigned int optlen)
 {
        int val;
        struct sctp_sock *sp = sctp_sk(sk);
@@ -2702,34 +2834,72 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int op
 }
 
 /*
- * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
- *
- * This socket option specifies the maximum size to put in any outgoing
- * SCTP chunk.  If a message is larger than this size it will be
+ * 8.1.16.  Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG)
+ * This option will get or set the maximum size to put in any outgoing
+ * SCTP DATA chunk.  If a message is larger than this size it will be
  * fragmented by SCTP into the specified size.  Note that the underlying
  * SCTP implementation may fragment into smaller sized chunks when the
  * PMTU of the underlying association is smaller than the value set by
- * the user.
+ * the user.  The default value for this option is '0' which indicates
+ * the user is NOT limiting fragmentation and only the PMTU will effect
+ * SCTP's choice of DATA chunk size.  Note also that values set larger
+ * than the maximum size of an IP datagram will effectively let SCTP
+ * control fragmentation (i.e. the same as setting this option to 0).
+ *
+ * The following structure is used to access and modify this parameter:
+ *
+ * struct sctp_assoc_value {
+ *   sctp_assoc_t assoc_id;
+ *   uint32_t assoc_value;
+ * };
+ *
+ * assoc_id:  This parameter is ignored for one-to-one style sockets.
+ *    For one-to-many style sockets this parameter indicates which
+ *    association the user is performing 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 specifies the maximum size in bytes.
  */
-static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen)
+static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen)
 {
+       struct sctp_assoc_value params;
        struct sctp_association *asoc;
-       struct list_head *pos;
        struct sctp_sock *sp = sctp_sk(sk);
        int val;
 
-       if (optlen < sizeof(int))
+       if (optlen == sizeof(int)) {
+               printk(KERN_WARNING
+                  "SCTP: Use of int in maxseg socket option deprecated\n");
+               printk(KERN_WARNING
+                  "SCTP: Use struct sctp_assoc_value instead\n");
+               if (copy_from_user(&val, optval, optlen))
+                       return -EFAULT;
+               params.assoc_id = 0;
+       } else if (optlen == sizeof(struct sctp_assoc_value)) {
+               if (copy_from_user(&params, optval, optlen))
+                       return -EFAULT;
+               val = params.assoc_value;
+       } else
                return -EINVAL;
-       if (get_user(val, (int __user *)optval))
-               return -EFAULT;
+
        if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)))
                return -EINVAL;
-       sp->user_frag = 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->pathmtu);
+       asoc = sctp_id2assoc(sk, params.assoc_id);
+       if (!asoc && params.assoc_id && sctp_style(sk, UDP))
+               return -EINVAL;
+
+       if (asoc) {
+               if (val == 0) {
+                       val = asoc->pathmtu;
+                       val -= sp->pf->af->net_header_len;
+                       val -= sizeof(struct sctphdr) +
+                                       sizeof(struct sctp_data_chunk);
+               }
+               asoc->user_frag = val;
+               asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
+       } else {
+               sp->user_frag = val;
        }
 
        return 0;
@@ -2745,7 +2915,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optl
  *   set primary request:
  */
 static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval,
-                                            int optlen)
+                                            unsigned int optlen)
 {
        struct sctp_sock        *sp;
        struct sctp_endpoint    *ep;
@@ -2796,7 +2966,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
 }
 
 static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval,
-                                         int optlen)
+                                           unsigned int optlen)
 {
        struct sctp_setadaptation adaptation;
 
@@ -2825,7 +2995,7 @@ static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval
  * saved with outbound messages.
  */
 static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
-                                  int optlen)
+                                  unsigned int optlen)
 {
        struct sctp_assoc_value params;
        struct sctp_sock *sp;
@@ -2876,7 +3046,7 @@ static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
  */
 static int sctp_setsockopt_fragment_interleave(struct sock *sk,
                                               char __user *optval,
-                                              int optlen)
+                                              unsigned int optlen)
 {
        int val;
 
@@ -2891,18 +3061,25 @@ static int sctp_setsockopt_fragment_interleave(struct sock *sk,
 }
 
 /*
- * 7.1.25.  Set or Get the sctp partial delivery point
+ * 8.1.21.  Set or Get the SCTP Partial Delivery Point
  *       (SCTP_PARTIAL_DELIVERY_POINT)
+ *
  * This option will set or get the SCTP partial delivery point.  This
  * point is the size of a message where the partial delivery API will be
  * invoked to help free up rwnd space for the peer.  Setting this to a
- * lower value will cause partial delivery's to happen more often.  The
+ * lower value will cause partial deliveries to happen more often.  The
  * calls argument is an integer that sets or gets the partial delivery
- * point.
+ * point.  Note also that the call will fail if the user attempts to set
+ * this value larger than the socket receive buffer size.
+ *
+ * Note that any single message having a length smaller than or equal to
+ * the SCTP partial delivery point will be delivered in one single read
+ * call as long as the user provided buffer is large enough to hold the
+ * message.
  */
 static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
                                                  char __user *optval,
-                                                 int optlen)
+                                                 unsigned int optlen)
 {
        u32 val;
 
@@ -2911,6 +3088,12 @@ static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
        if (get_user(val, (int __user *)optval))
                return -EFAULT;
 
+       /* Note: We double the receive buffer from what the user sets
+        * it to be, also initial rwnd is based on rcvbuf/2.
+        */
+       if (val > (sk->sk_rcvbuf >> 1))
+               return -EINVAL;
+
        sctp_sk(sk)->pd_point = val;
 
        return 0; /* is this the right error code? */
@@ -2929,19 +3112,38 @@ static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
  */
 static int sctp_setsockopt_maxburst(struct sock *sk,
                                    char __user *optval,
-                                   int optlen)
+                                   unsigned int optlen)
 {
+       struct sctp_assoc_value params;
+       struct sctp_sock *sp;
+       struct sctp_association *asoc;
        int val;
-
-       if (optlen != sizeof(int))
+       int assoc_id = 0;
+
+       if (optlen == sizeof(int)) {
+               printk(KERN_WARNING
+                  "SCTP: Use of int in max_burst socket option deprecated\n");
+               printk(KERN_WARNING
+                  "SCTP: Use struct sctp_assoc_value instead\n");
+               if (copy_from_user(&val, optval, optlen))
+                       return -EFAULT;
+       } else if (optlen == sizeof(struct sctp_assoc_value)) {
+               if (copy_from_user(&params, optval, optlen))
+                       return -EFAULT;
+               val = params.assoc_value;
+               assoc_id = params.assoc_id;
+       } else
                return -EINVAL;
-       if (get_user(val, (int __user *)optval))
-               return -EFAULT;
 
-       if (val < 0)
-               return -EINVAL;
+       sp = sctp_sk(sk);
 
-       sctp_sk(sk)->max_burst = val;
+       if (assoc_id != 0) {
+               asoc = sctp_id2assoc(sk, assoc_id);
+               if (!asoc)
+                       return -EINVAL;
+               asoc->max_burst = val;
+       } else
+               sp->max_burst = val;
 
        return 0;
 }
@@ -2954,11 +3156,14 @@ static int sctp_setsockopt_maxburst(struct sock *sk,
  * will only effect future associations on the socket.
  */
 static int sctp_setsockopt_auth_chunk(struct sock *sk,
-                                   char __user *optval,
-                                   int optlen)
+                                     char __user *optval,
+                                     unsigned int optlen)
 {
        struct sctp_authchunk val;
 
+       if (!sctp_auth_enable)
+               return -EACCES;
+
        if (optlen != sizeof(struct sctp_authchunk))
                return -EINVAL;
        if (copy_from_user(&val, optval, optlen))
@@ -2983,12 +3188,16 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk,
  * endpoint requires the peer to use.
  */
 static int sctp_setsockopt_hmac_ident(struct sock *sk,
-                                   char __user *optval,
-                                   int optlen)
+                                     char __user *optval,
+                                     unsigned int optlen)
 {
        struct sctp_hmacalgo *hmacs;
+       u32 idents;
        int err;
 
+       if (!sctp_auth_enable)
+               return -EACCES;
+
        if (optlen < sizeof(struct sctp_hmacalgo))
                return -EINVAL;
 
@@ -3001,8 +3210,9 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,
                goto out;
        }
 
-       if (hmacs->shmac_num_idents == 0 ||
-           hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) {
+       idents = hmacs->shmac_num_idents;
+       if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS ||
+           (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) {
                err = -EINVAL;
                goto out;
        }
@@ -3021,12 +3231,15 @@ out:
  */
 static int sctp_setsockopt_auth_key(struct sock *sk,
                                    char __user *optval,
-                                   int optlen)
+                                   unsigned int optlen)
 {
        struct sctp_authkey *authkey;
        struct sctp_association *asoc;
        int ret;
 
+       if (!sctp_auth_enable)
+               return -EACCES;
+
        if (optlen <= sizeof(struct sctp_authkey))
                return -EINVAL;
 
@@ -3039,6 +3252,11 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
                goto out;
        }
 
+       if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        asoc = sctp_id2assoc(sk, authkey->sca_assoc_id);
        if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) {
                ret = -EINVAL;
@@ -3058,12 +3276,15 @@ out:
  * the association shared key.
  */
 static int sctp_setsockopt_active_key(struct sock *sk,
-                                       char __user *optval,
-                                       int optlen)
+                                     char __user *optval,
+                                     unsigned int optlen)
 {
        struct sctp_authkeyid val;
        struct sctp_association *asoc;
 
+       if (!sctp_auth_enable)
+               return -EACCES;
+
        if (optlen != sizeof(struct sctp_authkeyid))
                return -EINVAL;
        if (copy_from_user(&val, optval, optlen))
@@ -3083,12 +3304,15 @@ static int sctp_setsockopt_active_key(struct sock *sk,
  * This set option will delete a shared secret key from use.
  */
 static int sctp_setsockopt_del_key(struct sock *sk,
-                                       char __user *optval,
-                                       int optlen)
+                                  char __user *optval,
+                                  unsigned int optlen)
 {
        struct sctp_authkeyid val;
        struct sctp_association *asoc;
 
+       if (!sctp_auth_enable)
+               return -EACCES;
+
        if (optlen != sizeof(struct sctp_authkeyid))
                return -EINVAL;
        if (copy_from_user(&val, optval, optlen))
@@ -3124,7 +3348,7 @@ static int sctp_setsockopt_del_key(struct sock *sk,
  *   optlen  - the size of the buffer.
  */
 SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
-                               char __user *optval, int optlen)
+                               char __user *optval, unsigned int optlen)
 {
        int retval = 0;
 
@@ -3158,10 +3382,18 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
                                               optlen, SCTP_BINDX_REM_ADDR);
                break;
 
+       case SCTP_SOCKOPT_CONNECTX_OLD:
+               /* 'optlen' is the size of the addresses buffer. */
+               retval = sctp_setsockopt_connectx_old(sk,
+                                           (struct sockaddr __user *)optval,
+                                           optlen);
+               break;
+
        case SCTP_SOCKOPT_CONNECTX:
                /* 'optlen' is the size of the addresses buffer. */
-               retval = sctp_setsockopt_connectx(sk, (struct sockaddr __user *)optval,
-                                              optlen);
+               retval = sctp_setsockopt_connectx(sk,
+                                           (struct sockaddr __user *)optval,
+                                           optlen);
                break;
 
        case SCTP_DISABLE_FRAGMENTS:
@@ -3180,8 +3412,8 @@ 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);
+       case SCTP_DELAYED_ACK:
+               retval = sctp_setsockopt_delayed_ack(sk, optval, optlen);
                break;
        case SCTP_PARTIAL_DELIVERY_POINT:
                retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen);
@@ -3278,7 +3510,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr,
        sctp_lock_sock(sk);
 
        SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d\n",
-                         __FUNCTION__, sk, addr, addr_len);
+                         __func__, sk, addr, addr_len);
 
        /* Validate addr_len before calling common connect/connectx routine. */
        af = sctp_get_af_specific(addr->sa_family);
@@ -3288,7 +3520,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr,
                /* 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);
+               err = __sctp_connect(sk, addr, af->sockaddr_len, NULL);
        }
 
        sctp_release_sock(sk);
@@ -3440,6 +3672,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        sp->pathmaxrxt  = sctp_max_retrans_path;
        sp->pathmtu     = 0; // allow default discovery
        sp->sackdelay   = sctp_sack_timeout;
+       sp->sackfreq    = 2;
        sp->param_flags = SPP_HB_ENABLE |
                          SPP_PMTUD_ENABLE |
                          SPP_SACKDELAY_ENABLE;
@@ -3486,12 +3719,17 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        sp->hmac = NULL;
 
        SCTP_DBG_OBJCNT_INC(sock);
-       atomic_inc(&sctp_sockets_allocated);
+
+       local_bh_disable();
+       percpu_counter_inc(&sctp_sockets_allocated);
+       sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+       local_bh_enable();
+
        return 0;
 }
 
 /* Cleanup any SCTP per socket resources.  */
-SCTP_STATIC int sctp_destroy_sock(struct sock *sk)
+SCTP_STATIC void sctp_destroy_sock(struct sock *sk)
 {
        struct sctp_endpoint *ep;
 
@@ -3500,8 +3738,10 @@ SCTP_STATIC int sctp_destroy_sock(struct sock *sk)
        /* Release our hold on the endpoint. */
        ep = sctp_sk(sk)->ep;
        sctp_endpoint_free(ep);
-       atomic_dec(&sctp_sockets_allocated);
-       return 0;
+       local_bh_disable();
+       percpu_counter_dec(&sctp_sockets_allocated);
+       sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+       local_bh_enable();
 }
 
 /* API 4.1.7 shutdown() - TCP Style Syntax
@@ -3747,7 +3987,6 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
 {
        struct sock *sk = asoc->base.sk;
        struct socket *sock;
-       struct inet_sock *inetsk;
        struct sctp_af *af;
        int err = 0;
 
@@ -3762,18 +4001,18 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
        if (err < 0)
                return err;
 
-       /* Populate the fields of the newsk from the oldsk and migrate the
-        * asoc to the newsk.
-        */
-       sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
+       sctp_copy_sock(sock->sk, sk, asoc);
 
        /* Make peeled-off sockets more like 1-1 accepted sockets.
         * Set the daddr and initialize id to something more random
         */
        af = sctp_get_af_specific(asoc->peer.primary_addr.sa.sa_family);
        af->to_sk_daddr(&asoc->peer.primary_addr, sk);
-       inetsk = inet_sk(sock->sk);
-       inetsk->id = asoc->next_tsn ^ jiffies;
+
+       /* Populate the fields of the newsk from the oldsk and migrate the
+        * asoc to the newsk.
+        */
+       sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
 
        *sockp = sock;
 
@@ -3799,21 +4038,21 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
                goto out;
        }
 
-       SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __FUNCTION__, sk, asoc);
+       SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __func__, sk, asoc);
 
        retval = sctp_do_peeloff(asoc, &newsock);
        if (retval < 0)
                goto out;
 
        /* Map the socket to an unused fd that can be returned to the user.  */
-       retval = sock_map_fd(newsock);
+       retval = sock_map_fd(newsock, 0);
        if (retval < 0) {
                sock_release(newsock);
                goto out;
        }
 
        SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n",
-                         __FUNCTION__, sk, asoc, newsock->sk, retval);
+                         __func__, sk, asoc, newsock->sk, retval);
 
        /* Return the fd mapped to the new socket.  */
        peeloff.sd = retval;
@@ -3936,7 +4175,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
        /* 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)) {
+       if (!sctp_is_any(sk, ( union sctp_addr *)&params.spp_address)) {
                trans = sctp_addr_id2transport(sk, &params.spp_address,
                                               params.spp_assoc_id);
                if (!trans) {
@@ -3993,70 +4232,91 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
        return 0;
 }
 
-/* 7.1.23. 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;
- *   };
+/*
+ * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
+ *
+ * This option will effect the way delayed acks are performed.  This
+ * option allows you to get or set the delayed ack time, in
+ * milliseconds.  It also allows changing the delayed ack frequency.
+ * Changing the frequency to 1 disables the delayed sack algorithm.  If
+ * the assoc_id is 0, then this sets or gets the endpoints default
+ * values.  If the assoc_id field is non-zero, then the set or get
+ * effects the specified association for the one to many model (the
+ * assoc_id field is ignored by the one to one model).  Note that if
+ * sack_delay or sack_freq are 0 when setting this option, then the
+ * current values will remain unchanged.
+ *
+ * struct sctp_sack_info {
+ *     sctp_assoc_t            sack_assoc_id;
+ *     uint32_t                sack_delay;
+ *     uint32_t                sack_freq;
+ * };
  *
- *     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).
+ * sack_assoc_id -  This parameter, indicates which association the user
+ *    is performing 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.
+ * sack_delay -  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.
+ * sack_freq -  This parameter contains the number of packets that must
+ *    be received before a sack is sent without waiting for the delay
+ *    timer to expire.  The default value for this is 2, setting this
+ *    value to 1 will disable the delayed sack algorithm.
  */
-static int sctp_getsockopt_delayed_ack_time(struct sock *sk, int len,
+static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,
                                            char __user *optval,
                                            int __user *optlen)
 {
-       struct sctp_assoc_value  params;
+       struct sctp_sack_info    params;
        struct sctp_association *asoc = NULL;
        struct sctp_sock        *sp = sctp_sk(sk);
 
-       if (len < sizeof(struct sctp_assoc_value))
-               return - EINVAL;
-
-       len = sizeof(struct sctp_assoc_value);
+       if (len >= sizeof(struct sctp_sack_info)) {
+               len = sizeof(struct sctp_sack_info);
 
-       if (copy_from_user(&params, optval, len))
-               return -EFAULT;
+               if (copy_from_user(&params, optval, len))
+                       return -EFAULT;
+       } else if (len == sizeof(struct sctp_assoc_value)) {
+               printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
+                      "in delayed_ack socket option deprecated\n");
+               printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
+               if (copy_from_user(&params, optval, len))
+                       return -EFAULT;
+       } else
+               return - EINVAL;
 
-       /* Get association, if assoc_id != 0 and the socket is a one
+       /* Get association, if sack_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))
+       asoc = sctp_id2assoc(sk, params.sack_assoc_id);
+       if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP))
                return -EINVAL;
 
        if (asoc) {
                /* Fetch association values. */
-               if (asoc->param_flags & SPP_SACKDELAY_ENABLE)
-                       params.assoc_value = jiffies_to_msecs(
+               if (asoc->param_flags & SPP_SACKDELAY_ENABLE) {
+                       params.sack_delay = jiffies_to_msecs(
                                asoc->sackdelay);
-               else
-                       params.assoc_value = 0;
+                       params.sack_freq = asoc->sackfreq;
+
+               } else {
+                       params.sack_delay = 0;
+                       params.sack_freq = 1;
+               }
        } else {
                /* Fetch socket values. */
-               if (sp->param_flags & SPP_SACKDELAY_ENABLE)
-                       params.assoc_value  = sp->sackdelay;
-               else
-                       params.assoc_value  = 0;
+               if (sp->param_flags & SPP_SACKDELAY_ENABLE) {
+                       params.sack_delay  = sp->sackdelay;
+                       params.sack_freq = sp->sackfreq;
+               } else {
+                       params.sack_delay  = 0;
+                       params.sack_freq = 1;
+               }
        }
 
        if (copy_to_user(optval, &params, len))
@@ -4091,121 +4351,40 @@ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval
        return 0;
 }
 
-static int sctp_getsockopt_peer_addrs_num_old(struct sock *sk, int len,
-                                             char __user *optval,
-                                             int __user *optlen)
+
+static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
+                                     char __user *optval, int __user *optlen)
 {
-       sctp_assoc_t id;
        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(sctp_assoc_t))
+       if (len < sizeof(struct sctp_getaddrs))
                return -EINVAL;
 
-       if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
+       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, id);
+       asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
        if (!asoc)
                return -EINVAL;
 
-       list_for_each(pos, &asoc->peer.transport_addr_list) {
-               cnt ++;
-       }
-
-       return cnt;
-}
+       to = optval + offsetof(struct sctp_getaddrs,addrs);
+       space_left = len - offsetof(struct sctp_getaddrs,addrs);
 
-/*
- * 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_old getaddrs;
-       struct sctp_transport *from;
-       void __user *to;
-       union sctp_addr temp;
-       struct sctp_sock *sp = sctp_sk(sk);
-       int addrlen;
-
-       if (len < sizeof(struct sctp_getaddrs_old))
-               return -EINVAL;
-
-       len = sizeof(struct sctp_getaddrs_old);
-
-       if (copy_from_user(&getaddrs, optval, len))
-               return -EFAULT;
-
-       if (getaddrs.addr_num <= 0) return -EINVAL;
-
-       /* For UDP-style sockets, id specifies the association to query.  */
-       asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
-       if (!asoc)
-               return -EINVAL;
-
-       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));
-               sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
-               addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
-               if (copy_to_user(to, &temp, addrlen))
-                       return -EFAULT;
-               to += addrlen ;
-               cnt ++;
-               if (cnt >= getaddrs.addr_num) break;
-       }
-       getaddrs.addr_num = cnt;
-       if (put_user(len, optlen))
-               return -EFAULT;
-       if (copy_to_user(optval, &getaddrs, len))
-               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 - offsetof(struct sctp_getaddrs,addrs);
-
-       list_for_each(pos, &asoc->peer.transport_addr_list) {
-               from = list_entry(pos, struct sctp_transport, transports);
+       list_for_each_entry(from, &asoc->peer.transport_addr_list,
+                               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;
+               addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
                if (space_left < addrlen)
                        return -ENOMEM;
                if (copy_to_user(to, &temp, addrlen))
@@ -4224,110 +4403,6 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
        return 0;
 }
 
-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 sctp_sockaddr_entry *addr;
-       int cnt = 0;
-
-       if (len < sizeof(sctp_assoc_t))
-               return -EINVAL;
-
-       if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
-               return -EFAULT;
-
-       /*
-        *  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 == id) {
-               bp = &sctp_sk(sk)->ep->base.bind_addr;
-       } else {
-               asoc = sctp_id2assoc(sk, id);
-               if (!asoc)
-                       return -EINVAL;
-               bp = &asoc->base.bind_addr;
-       }
-
-       /* 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)) {
-                       rcu_read_lock();
-                       list_for_each_entry_rcu(addr,
-                                               &sctp_local_addr_list, list) {
-                               if (!addr->valid)
-                                       continue;
-
-                               if ((PF_INET == sk->sk_family) &&
-                                   (AF_INET6 == addr->a.sa.sa_family))
-                                       continue;
-
-                               cnt++;
-                       }
-                       rcu_read_unlock();
-               } else {
-                       cnt = 1;
-               }
-               goto done;
-       }
-
-       /* Protection on the bound address list is not needed,
-        * since in the socket option context we hold the socket lock,
-        * so there is no way that the bound address list can change.
-        */
-       list_for_each_entry(addr, &bp->address_list, list) {
-               cnt ++;
-       }
-done:
-       return cnt;
-}
-
-/* Helper function that copies local addresses to user and returns the number
- * of addresses copied.
- */
-static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
-                                       int max_addrs, void *to,
-                                       int *bytes_copied)
-{
-       struct sctp_sockaddr_entry *addr;
-       union sctp_addr temp;
-       int cnt = 0;
-       int addrlen;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) {
-               if (!addr->valid)
-                       continue;
-
-               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;
-               memcpy(to, &temp, addrlen);
-
-               to += addrlen;
-               *bytes_copied += addrlen;
-               cnt ++;
-               if (cnt >= max_addrs) break;
-       }
-       rcu_read_unlock();
-
-       return cnt;
-}
-
 static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
                            size_t space_left, int *bytes_copied)
 {
@@ -4344,7 +4419,14 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
                if ((PF_INET == sk->sk_family) &&
                    (AF_INET6 == addr->a.sa.sa_family))
                        continue;
+               if ((PF_INET6 == sk->sk_family) &&
+                   inet_v6_ipv6only(sk) &&
+                   (AF_INET == addr->a.sa.sa_family))
+                       continue;
                memcpy(&temp, &addr->a, sizeof(temp));
+               if (!temp.v4.sin_port)
+                       temp.v4.sin_port = htons(port);
+
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
                                                                &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
@@ -4364,106 +4446,6 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
        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;
-       int cnt = 0;
-       struct sctp_getaddrs_old getaddrs;
-       struct sctp_sockaddr_entry *addr;
-       void __user *to;
-       union sctp_addr temp;
-       struct sctp_sock *sp = sctp_sk(sk);
-       int addrlen;
-       int err = 0;
-       void *addrs;
-       void *buf;
-       int bytes_copied = 0;
-
-       if (len < sizeof(struct sctp_getaddrs_old))
-               return -EINVAL;
-
-       len = sizeof(struct sctp_getaddrs_old);
-       if (copy_from_user(&getaddrs, optval, len))
-               return -EFAULT;
-
-       if (getaddrs.addr_num <= 0) return -EINVAL;
-       /*
-        *  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;
-       } else {
-               asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
-               if (!asoc)
-                       return -EINVAL;
-               bp = &asoc->base.bind_addr;
-       }
-
-       to = getaddrs.addrs;
-
-       /* Allocate space for a local instance of packed array to hold all
-        * the data.  We store addresses here first and then put write them
-        * to the user in one shot.
-        */
-       addrs = kmalloc(sizeof(union sctp_addr) * getaddrs.addr_num,
-                       GFP_KERNEL);
-       if (!addrs)
-               return -ENOMEM;
-
-       /* 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_old(sk, bp->port,
-                                                  getaddrs.addr_num,
-                                                  addrs, &bytes_copied);
-                       goto copy_getaddrs;
-               }
-       }
-
-       buf = addrs;
-       /* Protection on the bound address list is not needed since
-        * in the socket option context we hold a socket lock and
-        * thus the bound address list can't change.
-        */
-       list_for_each_entry(addr, &bp->address_list, 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;
-               memcpy(buf, &temp, addrlen);
-               buf += addrlen;
-               bytes_copied += addrlen;
-               cnt ++;
-               if (cnt >= getaddrs.addr_num) break;
-       }
-
-copy_getaddrs:
-       /* copy the entire address list into the user provided space */
-       if (copy_to_user(to, addrs, bytes_copied)) {
-               err = -EFAULT;
-               goto error;
-       }
-
-       /* copy the leading structure back to user */
-       getaddrs.addr_num = cnt;
-       if (copy_to_user(optval, &getaddrs, len))
-               err = -EFAULT;
-
-error:
-       kfree(addrs);
-       return err;
-}
 
 static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
                                       char __user *optval, int __user *optlen)
@@ -4517,7 +4499,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
        if (sctp_list_single_entry(&bp->address_list)) {
                addr = list_entry(bp->address_list.next,
                                  struct sctp_sockaddr_entry, list);
-               if (sctp_is_any(&addr->a)) {
+               if (sctp_is_any(sk, &addr->a)) {
                        cnt = sctp_copy_laddrs(sk, bp->port, addrs,
                                                space_left, &bytes_copied);
                        if (cnt < 0) {
@@ -4914,30 +4896,69 @@ static int sctp_getsockopt_context(struct sock *sk, int len,
 }
 
 /*
- * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
- *
- * This socket option specifies the maximum size to put in any outgoing
- * SCTP chunk.  If a message is larger than this size it will be
+ * 8.1.16.  Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG)
+ * This option will get or set the maximum size to put in any outgoing
+ * SCTP DATA chunk.  If a message is larger than this size it will be
  * fragmented by SCTP into the specified size.  Note that the underlying
  * SCTP implementation may fragment into smaller sized chunks when the
  * PMTU of the underlying association is smaller than the value set by
- * the user.
+ * the user.  The default value for this option is '0' which indicates
+ * the user is NOT limiting fragmentation and only the PMTU will effect
+ * SCTP's choice of DATA chunk size.  Note also that values set larger
+ * than the maximum size of an IP datagram will effectively let SCTP
+ * control fragmentation (i.e. the same as setting this option to 0).
+ *
+ * The following structure is used to access and modify this parameter:
+ *
+ * struct sctp_assoc_value {
+ *   sctp_assoc_t assoc_id;
+ *   uint32_t assoc_value;
+ * };
+ *
+ * assoc_id:  This parameter is ignored for one-to-one style sockets.
+ *    For one-to-many style sockets this parameter indicates which
+ *    association the user is performing 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 specifies the maximum size in bytes.
  */
 static int sctp_getsockopt_maxseg(struct sock *sk, int len,
                                  char __user *optval, int __user *optlen)
 {
-       int val;
+       struct sctp_assoc_value params;
+       struct sctp_association *asoc;
 
-       if (len < sizeof(int))
+       if (len == sizeof(int)) {
+               printk(KERN_WARNING
+                  "SCTP: Use of int in maxseg socket option deprecated\n");
+               printk(KERN_WARNING
+                  "SCTP: Use struct sctp_assoc_value instead\n");
+               params.assoc_id = 0;
+       } else if (len >= sizeof(struct sctp_assoc_value)) {
+               len = sizeof(struct sctp_assoc_value);
+               if (copy_from_user(&params, optval, sizeof(params)))
+                       return -EFAULT;
+       } else
                return -EINVAL;
 
-       len = sizeof(int);
+       asoc = sctp_id2assoc(sk, params.assoc_id);
+       if (!asoc && params.assoc_id && sctp_style(sk, UDP))
+               return -EINVAL;
+
+       if (asoc)
+               params.assoc_value = asoc->frag_point;
+       else
+               params.assoc_value = sctp_sk(sk)->user_frag;
 
-       val = sctp_sk(sk)->user_frag;
        if (put_user(len, optlen))
                return -EFAULT;
-       if (copy_to_user(optval, &val, len))
-               return -EFAULT;
+       if (len == sizeof(int)) {
+               if (copy_to_user(optval, &params.assoc_value, len))
+                       return -EFAULT;
+       } else {
+               if (copy_to_user(optval, &params, len))
+                       return -EFAULT;
+       }
 
        return 0;
 }
@@ -4997,38 +5018,71 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
                                    char __user *optval,
                                    int __user *optlen)
 {
-       int val;
+       struct sctp_assoc_value params;
+       struct sctp_sock *sp;
+       struct sctp_association *asoc;
 
-       if (len < sizeof(int))
+       if (len == sizeof(int)) {
+               printk(KERN_WARNING
+                  "SCTP: Use of int in max_burst socket option deprecated\n");
+               printk(KERN_WARNING
+                  "SCTP: Use struct sctp_assoc_value instead\n");
+               params.assoc_id = 0;
+       } else if (len >= sizeof(struct sctp_assoc_value)) {
+               len = sizeof(struct sctp_assoc_value);
+               if (copy_from_user(&params, optval, len))
+                       return -EFAULT;
+       } else
                return -EINVAL;
 
-       len = sizeof(int);
+       sp = sctp_sk(sk);
 
-       val = sctp_sk(sk)->max_burst;
-       if (put_user(len, optlen))
-               return -EFAULT;
-       if (copy_to_user(optval, &val, len))
-               return -EFAULT;
+       if (params.assoc_id != 0) {
+               asoc = sctp_id2assoc(sk, params.assoc_id);
+               if (!asoc)
+                       return -EINVAL;
+               params.assoc_value = asoc->max_burst;
+       } else
+               params.assoc_value = sp->max_burst;
+
+       if (len == sizeof(int)) {
+               if (copy_to_user(optval, &params.assoc_value, len))
+                       return -EFAULT;
+       } else {
+               if (copy_to_user(optval, &params, len))
+                       return -EFAULT;
+       }
+
+       return 0;
 
-       return -ENOTSUPP;
 }
 
 static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
                                    char __user *optval, int __user *optlen)
 {
+       struct sctp_hmacalgo  __user *p = (void __user *)optval;
        struct sctp_hmac_algo_param *hmacs;
-       __u16 param_len;
+       __u16 data_len = 0;
+       u32 num_idents;
+
+       if (!sctp_auth_enable)
+               return -EACCES;
 
        hmacs = sctp_sk(sk)->ep->auth_hmacs_list;
-       param_len = ntohs(hmacs->param_hdr.length);
+       data_len = ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t);
 
-       if (len < param_len)
+       if (len < sizeof(struct sctp_hmacalgo) + data_len)
                return -EINVAL;
+
+       len = sizeof(struct sctp_hmacalgo) + data_len;
+       num_idents = data_len / sizeof(u16);
+
        if (put_user(len, optlen))
                return -EFAULT;
-       if (copy_to_user(optval, hmacs->hmac_ids, len))
+       if (put_user(num_idents, &p->shmac_num_idents))
+               return -EFAULT;
+       if (copy_to_user(p->shmac_idents, hmacs->hmac_ids, data_len))
                return -EFAULT;
-
        return 0;
 }
 
@@ -5038,6 +5092,9 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
        struct sctp_authkeyid val;
        struct sctp_association *asoc;
 
+       if (!sctp_auth_enable)
+               return -EACCES;
+
        if (len < sizeof(struct sctp_authkeyid))
                return -EINVAL;
        if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid)))
@@ -5052,58 +5109,78 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
        else
                val.scact_keynumber = sctp_sk(sk)->ep->active_key_id;
 
+       len = sizeof(struct sctp_authkeyid);
+       if (put_user(len, optlen))
+               return -EFAULT;
+       if (copy_to_user(optval, &val, len))
+               return -EFAULT;
+
        return 0;
 }
 
 static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
                                    char __user *optval, int __user *optlen)
 {
+       struct sctp_authchunks __user *p = (void __user *)optval;
        struct sctp_authchunks val;
        struct sctp_association *asoc;
        struct sctp_chunks_param *ch;
+       u32    num_chunks = 0;
        char __user *to;
 
-       if (len <= sizeof(struct sctp_authchunks))
+       if (!sctp_auth_enable)
+               return -EACCES;
+
+       if (len < sizeof(struct sctp_authchunks))
                return -EINVAL;
 
        if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
                return -EFAULT;
 
-       to = val.gauth_chunks;
+       to = p->gauth_chunks;
        asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
        if (!asoc)
                return -EINVAL;
 
        ch = asoc->peer.peer_chunks;
+       if (!ch)
+               goto num;
 
        /* See if the user provided enough room for all the data */
-       if (len < ntohs(ch->param_hdr.length))
+       num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t);
+       if (len < num_chunks)
                return -EINVAL;
 
-       len = ntohs(ch->param_hdr.length);
-       if (put_user(len, optlen))
+       if (copy_to_user(to, ch->chunks, num_chunks))
                return -EFAULT;
-       if (copy_to_user(to, ch->chunks, len))
+num:
+       len = sizeof(struct sctp_authchunks) + num_chunks;
+       if (put_user(len, optlen)) return -EFAULT;
+       if (put_user(num_chunks, &p->gauth_number_of_chunks))
                return -EFAULT;
-
        return 0;
 }
 
 static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
                                    char __user *optval, int __user *optlen)
 {
+       struct sctp_authchunks __user *p = (void __user *)optval;
        struct sctp_authchunks val;
        struct sctp_association *asoc;
        struct sctp_chunks_param *ch;
+       u32    num_chunks = 0;
        char __user *to;
 
-       if (len <= sizeof(struct sctp_authchunks))
+       if (!sctp_auth_enable)
+               return -EACCES;
+
+       if (len < sizeof(struct sctp_authchunks))
                return -EINVAL;
 
        if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
                return -EFAULT;
 
-       to = val.gauth_chunks;
+       to = p->gauth_chunks;
        asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
        if (!asoc && val.gauth_assoc_id && sctp_style(sk, UDP))
                return -EINVAL;
@@ -5113,13 +5190,52 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
        else
                ch = sctp_sk(sk)->ep->auth_chunk_list;
 
-       if (len < ntohs(ch->param_hdr.length))
+       if (!ch)
+               goto num;
+
+       num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t);
+       if (len < sizeof(struct sctp_authchunks) + num_chunks)
+               return -EINVAL;
+
+       if (copy_to_user(to, ch->chunks, num_chunks))
+               return -EFAULT;
+num:
+       len = sizeof(struct sctp_authchunks) + num_chunks;
+       if (put_user(len, optlen))
+               return -EFAULT;
+       if (put_user(num_chunks, &p->gauth_number_of_chunks))
+               return -EFAULT;
+
+       return 0;
+}
+
+/*
+ * 8.2.5.  Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER)
+ * This option gets the current number of associations that are attached
+ * to a one-to-many style socket.  The option value is an uint32_t.
+ */
+static int sctp_getsockopt_assoc_number(struct sock *sk, int len,
+                                   char __user *optval, int __user *optlen)
+{
+       struct sctp_sock *sp = sctp_sk(sk);
+       struct sctp_association *asoc;
+       u32 val = 0;
+
+       if (sctp_style(sk, TCP))
+               return -EOPNOTSUPP;
+
+       if (len < sizeof(u32))
                return -EINVAL;
 
-       len = ntohs(ch->param_hdr.length);
+       len = sizeof(u32);
+
+       list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
+               val++;
+       }
+
        if (put_user(len, optlen))
                return -EFAULT;
-       if (copy_to_user(to, ch->chunks, len))
+       if (copy_to_user(optval, &val, len))
                return -EFAULT;
 
        return 0;
@@ -5173,29 +5289,13 @@ 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,
+       case SCTP_DELAYED_ACK:
+               retval = sctp_getsockopt_delayed_ack(sk, len, optval,
                                                          optlen);
                break;
        case SCTP_INITMSG:
                retval = sctp_getsockopt_initmsg(sk, len, optval, optlen);
                break;
-       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_OLD:
-               retval = sctp_getsockopt_local_addrs_old(sk, len, optval,
-                                                        optlen);
-               break;
        case SCTP_GET_PEER_ADDRS:
                retval = sctp_getsockopt_peer_addrs(sk, len, optval,
                                                    optlen);
@@ -5204,6 +5304,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_local_addrs(sk, len, optval,
                                                     optlen);
                break;
+       case SCTP_SOCKOPT_CONNECTX3:
+               retval = sctp_getsockopt_connectx3(sk, len, optval, optlen);
+               break;
        case SCTP_DEFAULT_SEND_PARAM:
                retval = sctp_getsockopt_default_send_param(sk, len,
                                                            optval, optlen);
@@ -5267,6 +5370,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_local_auth_chunks(sk, len, optval,
                                                        optlen);
                break;
+       case SCTP_GET_ASSOC_NUMBER:
+               retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -5305,6 +5411,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 {
        struct sctp_bind_hashbucket *head; /* hash list */
        struct sctp_bind_bucket *pp; /* hash list port iterator */
+       struct hlist_node *node;
        unsigned short snum;
        int ret;
 
@@ -5315,20 +5422,23 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 
        if (snum == 0) {
                /* Search for an available port. */
-               unsigned int low = sysctl_local_port_range[0];
-               unsigned int high = sysctl_local_port_range[1];
-               unsigned int remaining = (high - low) + 1;
-               unsigned int rover = net_random() % remaining + low;
-               int index;
+               int low, high, remaining, index;
+               unsigned int rover;
+
+               inet_get_local_port_range(&low, &high);
+               remaining = (high - low) + 1;
+               rover = net_random() % remaining + low;
 
                do {
                        rover++;
                        if ((rover < low) || (rover > high))
                                rover = low;
+                       if (inet_is_reserved_local_port(rover))
+                               continue;
                        index = sctp_phashfn(rover);
                        head = &sctp_port_hashtable[index];
                        sctp_spin_lock(&head->lock);
-                       for (pp = head->chain; pp; pp = pp->next)
+                       sctp_for_each_hentry(pp, node, &head->chain)
                                if (pp->port == rover)
                                        goto next;
                        break;
@@ -5355,7 +5465,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                 */
                head = &sctp_port_hashtable[sctp_phashfn(snum)];
                sctp_spin_lock(&head->lock);
-               for (pp = head->chain; pp; pp = pp->next) {
+               sctp_for_each_hentry(pp, node, &head->chain) {
                        if (pp->port == snum)
                                goto pp_found;
                }
@@ -5371,7 +5481,6 @@ pp_found:
                 */
                int reuse = sk->sk_reuse;
                struct sock *sk2;
-               struct hlist_node *node;
 
                SCTP_DEBUG_PRINTK("sctp_get_port() found a possible match\n");
                if (pp->fastreuse && sk->sk_reuse &&
@@ -5392,12 +5501,13 @@ pp_found:
                        struct sctp_endpoint *ep2;
                        ep2 = sctp_sk(sk2)->ep;
 
-                       if (reuse && sk2->sk_reuse &&
-                           sk2->sk_state != SCTP_SS_LISTENING)
+                       if (sk == sk2 ||
+                           (reuse && sk2->sk_reuse &&
+                            sk2->sk_state != SCTP_SS_LISTENING))
                                continue;
 
-                       if (sctp_bind_addr_match(&ep2->base.bind_addr, addr,
-                                                sctp_sk(sk))) {
+                       if (sctp_bind_addr_conflict(&ep2->base.bind_addr, addr,
+                                                sctp_sk(sk2), sctp_sk(sk))) {
                                ret = (long)sk2;
                                goto fail_unlock;
                        }
@@ -5429,7 +5539,7 @@ pp_not_found:
         */
 success:
        if (!sctp_sk(sk)->bind_hash) {
-               inet_sk(sk)->num = snum;
+               inet_sk(sk)->inet_num = snum;
                sk_add_bind_node(sk, &pp->owner);
                sctp_sk(sk)->bind_hash = pp;
        }
@@ -5463,37 +5573,28 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
 }
 
 /*
- * 3.1.3 listen() - UDP Style Syntax
- *
- *   By default, new associations are not accepted for UDP style sockets.
- *   An application uses listen() to mark a socket as being able to
- *   accept new associations.
+ *  Move a socket to LISTENING state.
  */
-SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
+SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog)
 {
        struct sctp_sock *sp = sctp_sk(sk);
        struct sctp_endpoint *ep = sp->ep;
+       struct crypto_hash *tfm = NULL;
 
-       /* Only UDP style sockets that are not peeled off are allowed to
-        * listen().
-        */
-       if (!sctp_style(sk, UDP))
-               return -EINVAL;
-
-       /* If backlog is zero, disable listening. */
-       if (!backlog) {
-               if (sctp_sstate(sk, CLOSED))
-                       return 0;
-
-               sctp_unhash_endpoint(ep);
-               sk->sk_state = SCTP_SS_CLOSED;
-               return 0;
+       /* Allocate HMAC for generating cookie. */
+       if (!sctp_sk(sk)->hmac && sctp_hmac_alg) {
+               tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
+               if (IS_ERR(tfm)) {
+                       if (net_ratelimit()) {
+                               printk(KERN_INFO
+                                      "SCTP: failed to load transform for %s: %ld\n",
+                                       sctp_hmac_alg, PTR_ERR(tfm));
+                       }
+                       return -ENOSYS;
+               }
+               sctp_sk(sk)->hmac = tfm;
        }
 
-       /* Return if we are already listening. */
-       if (sctp_sstate(sk, LISTENING))
-               return 0;
-
        /*
         * If a bind() or sctp_bindx() is not called prior to a listen()
         * call that allows new associations to be accepted, the system
@@ -5504,118 +5605,81 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
         * extensions draft, but follows the practice as seen in TCP
         * sockets.
         *
-        * Additionally, turn off fastreuse flag since we are not listening
         */
        sk->sk_state = SCTP_SS_LISTENING;
        if (!ep->base.bind_addr.port) {
                if (sctp_autobind(sk))
                        return -EAGAIN;
-       } else
-               sctp_sk(sk)->bind_hash->fastreuse = 0;
-
-       sctp_hash_endpoint(ep);
-       return 0;
-}
-
-/*
- * 4.1.3 listen() - TCP Style Syntax
- *
- *   Applications uses listen() to ready the SCTP endpoint for accepting
- *   inbound associations.
- */
-SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
-{
-       struct sctp_sock *sp = sctp_sk(sk);
-       struct sctp_endpoint *ep = sp->ep;
-
-       /* If backlog is zero, disable listening. */
-       if (!backlog) {
-               if (sctp_sstate(sk, CLOSED))
-                       return 0;
-
-               sctp_unhash_endpoint(ep);
-               sk->sk_state = SCTP_SS_CLOSED;
-               return 0;
+       } else {
+               if (sctp_get_port(sk, inet_sk(sk)->inet_num)) {
+                       sk->sk_state = SCTP_SS_CLOSED;
+                       return -EADDRINUSE;
+               }
        }
 
-       if (sctp_sstate(sk, LISTENING))
-               return 0;
-
-       /*
-        * If a bind() or sctp_bindx() is not called prior to a listen()
-        * call that allows new associations to be accepted, the system
-        * picks an ephemeral port and will choose an address set equivalent
-        * to binding with a wildcard address.
-        *
-        * This is not currently spelled out in the SCTP sockets
-        * extensions draft, but follows the practice as seen in TCP
-        * sockets.
-        */
-       sk->sk_state = SCTP_SS_LISTENING;
-       if (!ep->base.bind_addr.port) {
-               if (sctp_autobind(sk))
-                       return -EAGAIN;
-       } else
-               sctp_sk(sk)->bind_hash->fastreuse = 0;
-
        sk->sk_max_ack_backlog = backlog;
        sctp_hash_endpoint(ep);
        return 0;
 }
 
 /*
+ * 4.1.3 / 5.1.3 listen()
+ *
+ *   By default, new associations are not accepted for UDP style sockets.
+ *   An application uses listen() to mark a socket as being able to
+ *   accept new associations.
+ *
+ *   On TCP style sockets, applications use listen() to ready the SCTP
+ *   endpoint for accepting inbound associations.
+ *
+ *   On both types of endpoints a backlog of '0' disables listening.
+ *
  *  Move a socket to LISTENING state.
  */
 int sctp_inet_listen(struct socket *sock, int backlog)
 {
        struct sock *sk = sock->sk;
-       struct crypto_hash *tfm = NULL;
+       struct sctp_endpoint *ep = sctp_sk(sk)->ep;
        int err = -EINVAL;
 
        if (unlikely(backlog < 0))
-               goto out;
+               return err;
 
        sctp_lock_sock(sk);
 
+       /* Peeled-off sockets are not allowed to listen().  */
+       if (sctp_style(sk, UDP_HIGH_BANDWIDTH))
+               goto out;
+
        if (sock->state != SS_UNCONNECTED)
                goto out;
 
-       /* Allocate HMAC for generating cookie. */
-       if (sctp_hmac_alg) {
-               tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
-               if (IS_ERR(tfm)) {
-                       if (net_ratelimit()) {
-                               printk(KERN_INFO
-                                      "SCTP: failed to load transform for %s: %ld\n",
-                                       sctp_hmac_alg, PTR_ERR(tfm));
-                       }
-                       err = -ENOSYS;
+       /* If backlog is zero, disable listening. */
+       if (!backlog) {
+               if (sctp_sstate(sk, CLOSED))
                        goto out;
-               }
-       }
 
-       switch (sock->type) {
-       case SOCK_SEQPACKET:
-               err = sctp_seqpacket_listen(sk, backlog);
-               break;
-       case SOCK_STREAM:
-               err = sctp_stream_listen(sk, backlog);
-               break;
-       default:
-               break;
+               err = 0;
+               sctp_unhash_endpoint(ep);
+               sk->sk_state = SCTP_SS_CLOSED;
+               if (sk->sk_reuse)
+                       sctp_sk(sk)->bind_hash->fastreuse = 1;
+               goto out;
        }
 
-       if (err)
-               goto cleanup;
+       /* If we are already listening, just update the backlog */
+       if (sctp_sstate(sk, LISTENING))
+               sk->sk_max_ack_backlog = backlog;
+       else {
+               err = sctp_listen_start(sk, backlog);
+               if (err)
+                       goto out;
+       }
 
-       /* Store away the transform reference. */
-       sctp_sk(sk)->hmac = tfm;
+       err = 0;
 out:
        sctp_release_sock(sk);
        return err;
-cleanup:
-       crypto_free_hash(tfm);
-       goto out;
 }
 
 /*
@@ -5637,7 +5701,7 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
        struct sctp_sock *sp = sctp_sk(sk);
        unsigned int mask;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       poll_wait(file, sk_sleep(sk), wait);
 
        /* A TCP-style listening socket becomes readable when the accept queue
         * is not empty.
@@ -5694,15 +5758,12 @@ static struct sctp_bind_bucket *sctp_bucket_create(
        struct sctp_bind_bucket *pp;
 
        pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC);
-       SCTP_DBG_OBJCNT_INC(bind_bucket);
        if (pp) {
+               SCTP_DBG_OBJCNT_INC(bind_bucket);
                pp->port = snum;
                pp->fastreuse = 0;
                INIT_HLIST_HEAD(&pp->owner);
-               if ((pp->next = head->chain) != NULL)
-                       pp->next->pprev = &pp->next;
-               head->chain = pp;
-               pp->pprev = &head->chain;
+               hlist_add_head(&pp->node, &head->chain);
        }
        return pp;
 }
@@ -5711,9 +5772,7 @@ static struct sctp_bind_bucket *sctp_bucket_create(
 static void sctp_bucket_destroy(struct sctp_bind_bucket *pp)
 {
        if (pp && hlist_empty(&pp->owner)) {
-               if (pp->next)
-                       pp->next->pprev = pp->pprev;
-               *(pp->pprev) = pp->next;
+               __hlist_del(&pp->node);
                kmem_cache_free(sctp_bucket_cachep, pp);
                SCTP_DBG_OBJCNT_DEC(bind_bucket);
        }
@@ -5723,14 +5782,14 @@ static void sctp_bucket_destroy(struct sctp_bind_bucket *pp)
 static inline void __sctp_put_port(struct sock *sk)
 {
        struct sctp_bind_hashbucket *head =
-               &sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->num)];
+               &sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->inet_num)];
        struct sctp_bind_bucket *pp;
 
        sctp_spin_lock(&head->lock);
        pp = sctp_sk(sk)->bind_hash;
        __sk_del_bind_node(sk);
        sctp_sk(sk)->bind_hash = NULL;
-       inet_sk(sk)->num = 0;
+       inet_sk(sk)->inet_num = 0;
        sctp_bucket_destroy(pp);
        sctp_spin_unlock(&head->lock);
 }
@@ -5757,7 +5816,7 @@ static int sctp_autobind(struct sock *sk)
        /* Initialize a local sockaddr structure to INADDR_ANY. */
        af = sctp_sk(sk)->pf->af;
 
-       port = htons(inet_sk(sk)->num);
+       port = htons(inet_sk(sk)->inet_num);
        af->inaddr_any(&autoaddr, port);
 
        return sctp_do_bind(sk, &autoaddr, af->sockaddr_len);
@@ -5806,11 +5865,12 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
                                  sctp_cmsgs_t *cmsgs)
 {
        struct cmsghdr *cmsg;
+       struct msghdr *my_msg = (struct msghdr *)msg;
 
        for (cmsg = CMSG_FIRSTHDR(msg);
             cmsg != NULL;
-            cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) {
-               if (!CMSG_OK(msg, cmsg))
+            cmsg = CMSG_NXTHDR(my_msg, cmsg)) {
+               if (!CMSG_OK(my_msg, cmsg))
                        return -EINVAL;
 
                /* Should we parse this header or ignore?  */
@@ -5882,7 +5942,7 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p)
        int error;
        DEFINE_WAIT(wait);
 
-       prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+       prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
        /* Socket errors? */
        error = sock_error(sk);
@@ -5919,14 +5979,14 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p)
        sctp_lock_sock(sk);
 
 ready:
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return 0;
 
 interrupted:
        error = sock_intr_errno(*timeo_p);
 
 out:
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        *err = error;
        return error;
 }
@@ -6000,16 +6060,17 @@ static void __sctp_write_space(struct sctp_association *asoc)
                        wake_up_interruptible(&asoc->wait);
 
                if (sctp_writeable(sk)) {
-                       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-                               wake_up_interruptible(sk->sk_sleep);
+                       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
+                               wake_up_interruptible(sk_sleep(sk));
 
                        /* Note that we try to include the Async I/O support
                         * here by modeling from the current TCP/UDP code.
                         * We have not tested with it yet.
                         */
-                       if (sock->fasync_list &&
+                       if (sock->wq->fasync_list &&
                            !(sk->sk_shutdown & SEND_SHUTDOWN))
-                               sock_wake_async(sock, 2, POLL_OUT);
+                               sock_wake_async(sock,
+                                               SOCK_WAKE_SPACE, POLL_OUT);
                }
        }
 }
@@ -6035,10 +6096,10 @@ static void sctp_wfree(struct sk_buff *skb)
        atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
 
        /*
-        * This undoes what is done via sk_charge_skb
+        * This undoes what is done via sctp_set_owner_w and sk_mem_charge
         */
        sk->sk_wmem_queued   -= skb->truesize;
-       sk->sk_forward_alloc += skb->truesize;
+       sk_mem_uncharge(sk, skb->truesize);
 
        sock_wfree(skb);
        __sctp_write_space(asoc);
@@ -6059,9 +6120,9 @@ void sctp_sock_rfree(struct sk_buff *skb)
        atomic_sub(event->rmem_len, &sk->sk_rmem_alloc);
 
        /*
-        * Mimic the behavior of sk_stream_rfree
+        * Mimic the behavior of sock_rfree
         */
-       sk->sk_forward_alloc += event->rmem_len;
+       sk_mem_uncharge(sk, event->rmem_len);
 }
 
 
@@ -6126,15 +6187,26 @@ do_nonblock:
        goto out;
 }
 
+void sctp_data_ready(struct sock *sk, int len)
+{
+       struct socket_wq *wq;
+
+       rcu_read_lock();
+       wq = rcu_dereference(sk->sk_wq);
+       if (wq_has_sleeper(wq))
+               wake_up_interruptible_sync_poll(&wq->wait, POLLIN |
+                                               POLLRDNORM | POLLRDBAND);
+       sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
+       rcu_read_unlock();
+}
+
 /* If socket sndbuf has changed, wake up all per association waiters.  */
 void sctp_write_space(struct sock *sk)
 {
        struct sctp_association *asoc;
-       struct list_head *pos;
 
        /* Wake up the tasks in each wait queue.  */
-       list_for_each(pos, &((sctp_sk(sk))->ep->asocs)) {
-               asoc = list_entry(pos, struct sctp_association, asocs);
+       list_for_each_entry(asoc, &((sctp_sk(sk))->ep->asocs), asocs) {
                __sctp_write_space(asoc);
        }
 }
@@ -6154,7 +6226,7 @@ static int sctp_writeable(struct sock *sk)
 {
        int amt = 0;
 
-       amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+       amt = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
        if (amt < 0)
                amt = 0;
        return amt;
@@ -6170,7 +6242,7 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p)
        long current_timeo = *timeo_p;
        DEFINE_WAIT(wait);
 
-       SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc,
+       SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __func__, asoc,
                          (long)(*timeo_p));
 
        /* Increment the association's refcnt.  */
@@ -6236,7 +6308,7 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo)
 
 
        for (;;) {
-               prepare_to_wait_exclusive(sk->sk_sleep, &wait,
+               prepare_to_wait_exclusive(sk_sleep(sk), &wait,
                                          TASK_INTERRUPTIBLE);
 
                if (list_empty(&ep->asocs)) {
@@ -6262,7 +6334,7 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo)
                        break;
        }
 
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
 
        return err;
 }
@@ -6272,7 +6344,7 @@ static void sctp_wait_for_close(struct sock *sk, long timeout)
        DEFINE_WAIT(wait);
 
        do {
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                if (list_empty(&sctp_sk(sk)->ep->asocs))
                        break;
                sctp_release_sock(sk);
@@ -6280,22 +6352,7 @@ static void sctp_wait_for_close(struct sock *sk, long timeout)
                sctp_lock_sock(sk);
        } while (!signal_pending(current) && timeout);
 
-       finish_wait(sk->sk_sleep, &wait);
-}
-
-static void sctp_sock_rfree_frag(struct sk_buff *skb)
-{
-       struct sk_buff *frag;
-
-       if (!skb->data_len)
-               goto done;
-
-       /* Don't forget the fragments. */
-       for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next)
-               sctp_sock_rfree_frag(frag);
-
-done:
-       sctp_sock_rfree(skb);
+       finish_wait(sk_sleep(sk), &wait);
 }
 
 static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk)
@@ -6306,13 +6363,55 @@ static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk)
                goto done;
 
        /* Don't forget the fragments. */
-       for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next)
+       skb_walk_frags(skb, frag)
                sctp_skb_set_owner_r_frag(frag, sk);
 
 done:
        sctp_skb_set_owner_r(skb, sk);
 }
 
+void sctp_copy_sock(struct sock *newsk, struct sock *sk,
+                   struct sctp_association *asoc)
+{
+       struct inet_sock *inet = inet_sk(sk);
+       struct inet_sock *newinet;
+
+       newsk->sk_type = sk->sk_type;
+       newsk->sk_bound_dev_if = sk->sk_bound_dev_if;
+       newsk->sk_flags = sk->sk_flags;
+       newsk->sk_no_check = sk->sk_no_check;
+       newsk->sk_reuse = sk->sk_reuse;
+
+       newsk->sk_shutdown = sk->sk_shutdown;
+       newsk->sk_destruct = inet_sock_destruct;
+       newsk->sk_family = sk->sk_family;
+       newsk->sk_protocol = IPPROTO_SCTP;
+       newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
+       newsk->sk_sndbuf = sk->sk_sndbuf;
+       newsk->sk_rcvbuf = sk->sk_rcvbuf;
+       newsk->sk_lingertime = sk->sk_lingertime;
+       newsk->sk_rcvtimeo = sk->sk_rcvtimeo;
+       newsk->sk_sndtimeo = sk->sk_sndtimeo;
+
+       newinet = inet_sk(newsk);
+
+       /* Initialize sk's sport, dport, rcv_saddr and daddr for
+        * getsockname() and getpeername()
+        */
+       newinet->inet_sport = inet->inet_sport;
+       newinet->inet_saddr = inet->inet_saddr;
+       newinet->inet_rcv_saddr = inet->inet_rcv_saddr;
+       newinet->inet_dport = htons(asoc->peer.port);
+       newinet->pmtudisc = inet->pmtudisc;
+       newinet->inet_id = asoc->next_tsn ^ jiffies;
+
+       newinet->uc_ttl = inet->uc_ttl;
+       newinet->mc_loop = 1;
+       newinet->mc_ttl = 1;
+       newinet->mc_index = 0;
+       newinet->mc_list = NULL;
+}
+
 /* Populate the fields of the newsk from the oldsk and migrate the assoc
  * and its messages to the newsk.
  */
@@ -6326,7 +6425,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
        struct sctp_endpoint *newep = newsp->ep;
        struct sk_buff *skb, *tmp;
        struct sctp_ulpevent *event;
-       int flags = 0;
+       struct sctp_bind_hashbucket *head;
 
        /* Migrate socket buffer sizes and all the socket level options to the
         * new socket.
@@ -6343,23 +6442,21 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
        newsp->hmac = NULL;
 
        /* Hook this new socket in to the bind_hash list. */
+       head = &sctp_port_hashtable[sctp_phashfn(inet_sk(oldsk)->inet_num)];
+       sctp_local_bh_disable();
+       sctp_spin_lock(&head->lock);
        pp = sctp_sk(oldsk)->bind_hash;
        sk_add_bind_node(newsk, &pp->owner);
        sctp_sk(newsk)->bind_hash = pp;
-       inet_sk(newsk)->num = inet_sk(oldsk)->num;
+       inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num;
+       sctp_spin_unlock(&head->lock);
+       sctp_local_bh_enable();
 
        /* Copy the bind_addr list from the original endpoint to the new
         * endpoint so that we can handle restarts properly
         */
-       if (PF_INET6 == assoc->base.sk->sk_family)
-               flags = SCTP_ADDR6_ALLOWED;
-       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);
+       sctp_bind_addr_dup(&newsp->ep->base.bind_addr,
+                               &oldsp->ep->base.bind_addr, GFP_KERNEL);
 
        /* Move any messages in the old socket's receive queue that are for the
         * peeled off association to the new socket's receive queue.
@@ -6367,7 +6464,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
        sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
                event = sctp_skb2event(skb);
                if (event->asoc == assoc) {
-                       sctp_sock_rfree_frag(skb);
                        __skb_unlink(skb, &oldsk->sk_receive_queue);
                        __skb_queue_tail(&newsk->sk_receive_queue, skb);
                        sctp_skb_set_owner_r_frag(skb, newsk);
@@ -6398,7 +6494,6 @@ 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) {
-                               sctp_sock_rfree_frag(skb);
                                __skb_unlink(skb, &oldsp->pd_lobby);
                                __skb_queue_tail(queue, skb);
                                sctp_skb_set_owner_r_frag(skb, newsk);
@@ -6413,15 +6508,11 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
 
        }
 
-       sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp) {
-               sctp_sock_rfree_frag(skb);
+       sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp)
                sctp_skb_set_owner_r_frag(skb, newsk);
-       }
 
-       sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp) {
-               sctp_sock_rfree_frag(skb);
+       sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp)
                sctp_skb_set_owner_r_frag(skb, newsk);
-       }
 
        /* Set the type of socket to indicate that it is peeled off from the
         * original UDP-style socket or created with the accept() call on a
@@ -6480,9 +6571,11 @@ struct proto sctp_prot = {
        .memory_pressure = &sctp_memory_pressure,
        .enter_memory_pressure = sctp_enter_memory_pressure,
        .memory_allocated = &sctp_memory_allocated,
+       .sockets_allocated = &sctp_sockets_allocated,
 };
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+
 struct proto sctpv6_prot = {
        .name           = "SCTPv6",
        .owner          = THIS_MODULE,
@@ -6510,5 +6603,6 @@ struct proto sctpv6_prot = {
        .memory_pressure = &sctp_memory_pressure,
        .enter_memory_pressure = sctp_enter_memory_pressure,
        .memory_allocated = &sctp_memory_allocated,
+       .sockets_allocated = &sctp_sockets_allocated,
 };
 #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */