fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / sctp / sm_make_chunk.c
index c2ca732..0b1ddb1 100644 (file)
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
-extern kmem_cache_t *sctp_chunk_cachep;
+extern struct kmem_cache *sctp_chunk_cachep;
+
+SCTP_STATIC
+struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
+                                  __u8 type, __u8 flags, int paylen);
+static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
+                                       const struct sctp_association *asoc,
+                                       const struct sctp_chunk *init_chunk,
+                                       int *cookie_len,
+                                       const __u8 *raw_addrs, int addrs_len);
+static int sctp_process_param(struct sctp_association *asoc,
+                             union sctp_params param,
+                             const union sctp_addr *peer_addr,
+                             gfp_t gfp);
 
 /* What was the inbound interface for this chunk? */
 int sctp_chunk_iif(const struct sctp_chunk *chunk)
@@ -98,7 +111,7 @@ static const struct sctp_paramhdr prsctp_param = {
  * provided chunk, as most cause codes will be embedded inside an
  * abort chunk.
  */
-void  sctp_init_cause(struct sctp_chunk *chunk, __u16 cause_code,
+void  sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,
                      const void *payload, size_t paylen)
 {
        sctp_errhdr_t err;
@@ -111,8 +124,8 @@ void  sctp_init_cause(struct sctp_chunk *chunk, __u16 cause_code,
        padlen = len % 4;
        err.length  = htons(len);
        len += padlen;
-       sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err);
-       chunk->subh.err_hdr = sctp_addto_chunk(chunk, paylen, payload);
+       chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err);
+       sctp_addto_chunk(chunk, paylen, payload);
 }
 
 /* 3.3.2 Initiation (INIT) (1)
@@ -161,16 +174,17 @@ void  sctp_init_cause(struct sctp_chunk *chunk, __u16 cause_code,
  */
 struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
                             const struct sctp_bind_addr *bp,
-                            int gfp, int vparam_len)
+                            gfp_t gfp, int vparam_len)
 {
        sctp_inithdr_t init;
        union sctp_params addrs;
        size_t chunksize;
        struct sctp_chunk *retval = NULL;
        int num_types, addrs_len = 0;
-       struct sctp_opt *sp;
+       struct sctp_sock *sp;
        sctp_supported_addrs_param_t sat;
-       __u16 types[2];
+       __be16 types[2];
+       sctp_adaptation_ind_param_t aiparam;
 
        /* RFC 2960 3.3.2 Initiation (INIT) (1)
         *
@@ -196,6 +210,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
        chunksize += sizeof(ecap_param);
        if (sctp_prsctp_enable)
                chunksize += sizeof(prsctp_param);
+       chunksize += sizeof(aiparam);
        chunksize += vparam_len;
 
        /* RFC 2960 3.3.2 Initiation (INIT) (1)
@@ -234,15 +249,18 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
        sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
        if (sctp_prsctp_enable)
                sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
+       aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
+       aiparam.param_hdr.length = htons(sizeof(aiparam));
+       aiparam.adaptation_ind = htonl(sp->adaptation_ind);
+       sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
 nodata:
-       if (addrs.v)
-               kfree(addrs.v);
+       kfree(addrs.v);
        return retval;
 }
 
 struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
                                 const struct sctp_chunk *chunk,
-                                int gfp, int unkparam_len)
+                                gfp_t gfp, int unkparam_len)
 {
        sctp_inithdr_t initack;
        struct sctp_chunk *retval;
@@ -251,6 +269,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        sctp_cookie_param_t *cookie;
        int cookie_len;
        size_t chunksize;
+       sctp_adaptation_ind_param_t aiparam;
 
        retval = NULL;
 
@@ -284,6 +303,8 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        if (asoc->peer.prsctp_capable)
                chunksize += sizeof(prsctp_param);
 
+       chunksize += sizeof(aiparam);
+
        /* Now allocate and fill out the chunk.  */
        retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize);
        if (!retval)
@@ -302,6 +323,11 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        if (asoc->peer.prsctp_capable)
                sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
 
+       aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
+       aiparam.param_hdr.length = htons(sizeof(aiparam));
+       aiparam.adaptation_ind = htonl(sctp_sk(asoc->base.sk)->adaptation_ind);
+       sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+
        /* We need to remove the const qualifier at this point.  */
        retval->asoc = (struct sctp_association *) asoc;
 
@@ -320,8 +346,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
 nomem_chunk:
        kfree(cookie);
 nomem_cookie:
-       if (addrs.v)
-               kfree(addrs.v);
+       kfree(addrs.v);
        return retval;
 }
 
@@ -527,7 +552,7 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,
        dp.ppid   = sinfo->sinfo_ppid;
 
        /* Set the flags for an unordered send.  */
-       if (sinfo->sinfo_flags & MSG_UNORDERED) {
+       if (sinfo->sinfo_flags & SCTP_UNORDERED) {
                flags |= SCTP_DATA_UNORDERED;
                dp.ssn = 0;
        } else
@@ -545,52 +570,6 @@ nodata:
        return retval;
 }
 
-/* Make a DATA chunk for the given association.  Populate the data
- * payload.
- */
-struct sctp_chunk *sctp_make_datafrag(struct sctp_association *asoc,
-                                const struct sctp_sndrcvinfo *sinfo,
-                                int data_len, const __u8 *data,
-                                __u8 flags, __u16 ssn)
-{
-       struct sctp_chunk *retval;
-
-       retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn);
-       if (retval)
-               sctp_addto_chunk(retval, data_len, data);
-
-       return retval;
-}
-
-/* Make a DATA chunk for the given association to ride on stream id
- * 'stream', with a payload id of 'payload', and a body of 'data'.
- */
-struct sctp_chunk *sctp_make_data(struct sctp_association *asoc,
-                            const struct sctp_sndrcvinfo *sinfo,
-                            int data_len, const __u8 *data)
-{
-       struct sctp_chunk *retval = NULL;
-
-       retval = sctp_make_data_empty(asoc, sinfo, data_len);
-       if (retval)
-               sctp_addto_chunk(retval, data_len, data);
-        return retval;
-}
-
-/* Make a DATA chunk for the given association to ride on stream id
- * 'stream', with a payload id of 'payload', and a body big enough to
- * hold 'data_len' octets of data.  We use this version when we need
- * to build the message AFTER allocating memory.
- */
-struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc,
-                                  const struct sctp_sndrcvinfo *sinfo,
-                                  int data_len)
-{
-       __u8 flags = SCTP_DATA_NOT_FRAG;
-
-       return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, 0);
-}
-
 /* Create a selective ackowledgement (SACK) for the given
  * association.  This reports on which TSN's we've seen to date,
  * including duplicates and gaps.
@@ -729,7 +708,9 @@ struct sctp_chunk *sctp_make_shutdown_complete(
        struct sctp_chunk *retval;
        __u8 flags = 0;
 
-       /* Maybe set the T-bit if we have no association. */
+       /* Set the T-bit if we have no association (vtag will be
+        * reflected)
+        */
        flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;
 
        retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0);
@@ -751,7 +732,7 @@ struct sctp_chunk *sctp_make_shutdown_complete(
 }
 
 /* Create an ABORT.  Note that we set the T bit if we have no
- * association.
+ * association, except when responding to an INIT (sctpimpguide 2.41).
  */
 struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,
                              const struct sctp_chunk *chunk,
@@ -760,8 +741,16 @@ struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,
        struct sctp_chunk *retval;
        __u8 flags = 0;
 
-       /* Maybe set the T-bit if we have no association.  */
-       flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;
+       /* Set the T-bit if we have no association and 'chunk' is not
+        * an INIT (vtag will be reflected).
+        */
+       if (!asoc) {
+               if (chunk && chunk->chunk_hdr &&
+                   chunk->chunk_hdr->type == SCTP_CID_INIT)
+                       flags = 0;
+               else
+                       flags = SCTP_CHUNK_FLAG_T;
+       }
 
        retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint);
 
@@ -786,7 +775,7 @@ struct sctp_chunk *sctp_make_abort_no_data(
        const struct sctp_chunk *chunk, __u32 tsn)
 {
        struct sctp_chunk *retval;
-       __u32 payload;
+       __be32 payload;
 
        retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t)
                                 + sizeof(tsn));
@@ -817,38 +806,26 @@ no_mem:
 
 /* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error.  */
 struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc,
-                                  const struct sctp_chunk *chunk,
-                                  const struct msghdr *msg)
+                                       const struct msghdr *msg,
+                                       size_t paylen)
 {
        struct sctp_chunk *retval;
-       void *payload = NULL, *payoff;
-       size_t paylen = 0;
-       struct iovec *iov = NULL;
-       int iovlen = 0;
-
-       if (msg) {
-               iov = msg->msg_iov;
-               iovlen = msg->msg_iovlen;
-               paylen = get_user_iov_size(iov, iovlen);
-       }
+       void *payload = NULL;
+       int err;
 
-       retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen);
+       retval = sctp_make_abort(asoc, NULL, sizeof(sctp_errhdr_t) + paylen);
        if (!retval)
                goto err_chunk;
 
        if (paylen) {
                /* Put the msg_iov together into payload.  */
-               payload = kmalloc(paylen, GFP_ATOMIC);
+               payload = kmalloc(paylen, GFP_KERNEL);
                if (!payload)
                        goto err_payload;
-               payoff = payload;
 
-               for (; iovlen > 0; --iovlen) {
-                       if (copy_from_user(payoff, iov->iov_base,iov->iov_len))
-                               goto err_copy;
-                       payoff += iov->iov_len;
-                       iov++;
-               }
+               err = memcpy_fromiovec(payload, msg->msg_iov, paylen);
+               if (err < 0)
+                       goto err_copy;
        }
 
        sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, payload, paylen);
@@ -867,6 +844,31 @@ err_chunk:
        return retval;
 }
 
+/* Make an ABORT chunk with a PROTOCOL VIOLATION cause code. */ 
+struct sctp_chunk *sctp_make_abort_violation(
+       const struct sctp_association *asoc,
+       const struct sctp_chunk *chunk,
+       const __u8   *payload,
+       const size_t paylen)
+{
+       struct sctp_chunk  *retval;
+       struct sctp_paramhdr phdr;
+
+       retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen
+                                       + sizeof(sctp_chunkhdr_t));
+       if (!retval)
+               goto end;
+
+       sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, payload, paylen);
+
+       phdr.type = htons(chunk->chunk_hdr->type);
+       phdr.length = chunk->chunk_hdr->length;
+       sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &phdr);
+
+end:
+       return retval;
+}
+
 /* Make a HEARTBEAT chunk.  */
 struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
                                  const struct sctp_transport *transport,
@@ -919,7 +921,7 @@ nodata:
 /* Create an Operation Error chunk with the specified space reserved.
  * This routine can be used for containing multiple causes in the chunk.
  */
-struct sctp_chunk *sctp_make_op_error_space(
+static struct sctp_chunk *sctp_make_op_error_space(
        const struct sctp_association *asoc,
        const struct sctp_chunk *chunk,
        size_t size)
@@ -949,7 +951,7 @@ nodata:
 /* Create an Operation Error chunk.  */
 struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
                                 const struct sctp_chunk *chunk,
-                                __u16 cause_code, const void *payload,
+                                __be16 cause_code, const void *payload,
                                 size_t paylen)
 {
        struct sctp_chunk *retval;
@@ -977,7 +979,7 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
 {
        struct sctp_chunk *retval;
 
-       retval = kmem_cache_alloc(sctp_chunk_cachep, SLAB_ATOMIC);
+       retval = kmem_cache_alloc(sctp_chunk_cachep, GFP_ATOMIC);
 
        if (!retval)
                goto nodata;
@@ -987,6 +989,7 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
                SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb);
        }
 
+       INIT_LIST_HEAD(&retval->list);
        retval->skb             = skb;
        retval->asoc            = (struct sctp_association *)asoc;
        retval->resent          = 0;
@@ -1020,7 +1023,6 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
        SCTP_DBG_OBJCNT_INC(chunk);
        atomic_set(&retval->refcnt, 1);
 
-
 nodata:
        return retval;
 }
@@ -1048,6 +1050,7 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk)
 /* Create a new chunk, setting the type and flags headers from the
  * arguments, reserving enough space for a 'paylen' byte payload.
  */
+SCTP_STATIC
 struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
                                   __u8 type, __u8 flags, int paylen)
 {
@@ -1100,8 +1103,7 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk)
 /* Possibly, free the chunk.  */
 void sctp_chunk_free(struct sctp_chunk *chunk)
 {
-       /* Make sure that we are not on any list.  */
-       skb_unlink((struct sk_buff *) chunk);
+       BUG_ON(!list_empty(&chunk->list));
        list_del_init(&chunk->transmitted_list);
 
        /* Release our reference on the message tracker. */
@@ -1188,15 +1190,14 @@ void sctp_chunk_assign_ssn(struct sctp_chunk *chunk)
        if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
                ssn = 0;
        } else {
-               sid = htons(chunk->subh.data_hdr->stream);
+               sid = ntohs(chunk->subh.data_hdr->stream);
                if (chunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG)
                        ssn = sctp_ssn_next(&chunk->asoc->ssnmap->out, sid);
                else
                        ssn = sctp_ssn_peek(&chunk->asoc->ssnmap->out, sid);
-               ssn = htons(ssn);
        }
 
-       chunk->subh.data_hdr->ssn = ssn;
+       chunk->subh.data_hdr->ssn = htons(ssn);
        chunk->has_ssn = 1;
 }
 
@@ -1217,7 +1218,8 @@ void sctp_chunk_assign_tsn(struct sctp_chunk *chunk)
 
 /* Create a CLOSED association to use with an incoming packet.  */
 struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
-                                       struct sctp_chunk *chunk, int gfp)
+                                       struct sctp_chunk *chunk,
+                                       gfp_t gfp)
 {
        struct sctp_association *asoc;
        struct sk_buff *skb;
@@ -1247,7 +1249,7 @@ fail:
 /* Build a cookie representing asoc.
  * This INCLUDES the param header needed to put the cookie in the INIT ACK.
  */
-sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
+static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
                                      const struct sctp_association *asoc,
                                      const struct sctp_chunk *init_chunk,
                                      int *cookie_len,
@@ -1260,7 +1262,12 @@ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
        unsigned int keylen;
        char *key;
 
-       headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE;
+       /* Header size is static data prior to the actual cookie, including
+        * any padding.
+        */
+       headersize = sizeof(sctp_paramhdr_t) + 
+                    (sizeof(struct sctp_signed_cookie) - 
+                     sizeof(struct sctp_cookie));
        bodysize = sizeof(struct sctp_cookie)
                + ntohs(init_chunk->chunk_hdr->length) + addrs_len;
 
@@ -1272,17 +1279,13 @@ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
                        - (bodysize % SCTP_COOKIE_MULTIPLE);
        *cookie_len = headersize + bodysize;
 
-       retval = (sctp_cookie_param_t *)kmalloc(*cookie_len, GFP_ATOMIC);
-
-       if (!retval) {
-               *cookie_len = 0;
-               goto nodata;
-       }
-
        /* Clear this memory since we are sending this data structure
         * out on the network.
         */
-       memset(retval, 0x00, *cookie_len);
+       retval = kzalloc(*cookie_len, GFP_ATOMIC);
+       if (!retval)
+               goto nodata;
+
        cookie = (struct sctp_signed_cookie *) retval->body;
 
        /* Set up the parameter header.  */
@@ -1297,6 +1300,9 @@ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
        /* Remember PR-SCTP capability. */
        cookie->c.prsctp_capable = asoc->peer.prsctp_capable;
 
+       /* Save adaptation indication in the cookie. */
+       cookie->c.adaptation_ind = asoc->peer.adaptation_ind;
+
        /* Set an expiration time for the cookie.  */
        do_gettimeofday(&cookie->c.expiration);
        TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration);
@@ -1310,40 +1316,57 @@ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
               ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len);
 
        if (sctp_sk(ep->base.sk)->hmac) {
+               struct hash_desc desc;
+
                /* Sign the message.  */
                sg.page = virt_to_page(&cookie->c);
                sg.offset = (unsigned long)(&cookie->c) % PAGE_SIZE;
                sg.length = bodysize;
                keylen = SCTP_SECRET_SIZE;
                key = (char *)ep->secret_key[ep->current_key];
+               desc.tfm = sctp_sk(ep->base.sk)->hmac;
+               desc.flags = 0;
 
-               sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen,
-                                &sg, 1, cookie->signature);
+               if (crypto_hash_setkey(desc.tfm, key, keylen) ||
+                   crypto_hash_digest(&desc, &sg, bodysize, cookie->signature))
+                       goto free_cookie;
        }
 
-nodata:
        return retval;
+
+free_cookie:
+       kfree(retval);
+nodata:
+       *cookie_len = 0;
+       return NULL;
 }
 
 /* Unpack the cookie from COOKIE ECHO chunk, recreating the association.  */
 struct sctp_association *sctp_unpack_cookie(
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
-       struct sctp_chunk *chunk, int gfp,
+       struct sctp_chunk *chunk, gfp_t gfp,
        int *error, struct sctp_chunk **errp)
 {
        struct sctp_association *retval = NULL;
        struct sctp_signed_cookie *cookie;
        struct sctp_cookie *bear_cookie;
        int headersize, bodysize, fixed_size;
-       __u8 digest[SCTP_SIGNATURE_SIZE];
+       __u8 *digest = ep->digest;
        struct scatterlist sg;
        unsigned int keylen, len;
        char *key;
        sctp_scope_t scope;
        struct sk_buff *skb = chunk->skb;
+       struct timeval tv;
+       struct hash_desc desc;
 
-       headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE;
+       /* Header size is static data prior to the actual cookie, including
+        * any padding.
+        */
+       headersize = sizeof(sctp_chunkhdr_t) +
+                    (sizeof(struct sctp_signed_cookie) - 
+                     sizeof(struct sctp_cookie));
        bodysize = ntohs(chunk->chunk_hdr->length) - headersize;
        fixed_size = headersize + sizeof(struct sctp_cookie);
 
@@ -1372,17 +1395,25 @@ struct sctp_association *sctp_unpack_cookie(
        sg.offset = (unsigned long)(bear_cookie) % PAGE_SIZE;
        sg.length = bodysize;
        key = (char *)ep->secret_key[ep->current_key];
+       desc.tfm = sctp_sk(ep->base.sk)->hmac;
+       desc.flags = 0;
 
-       memset(digest, 0x00, sizeof(digest));
-       sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg,
-                        1, digest);
+       memset(digest, 0x00, SCTP_SIGNATURE_SIZE);
+       if (crypto_hash_setkey(desc.tfm, key, keylen) ||
+           crypto_hash_digest(&desc, &sg, bodysize, digest)) {
+               *error = -SCTP_IERROR_NOMEM;
+               goto fail;
+       }
 
        if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
                /* Try the previous key. */
                key = (char *)ep->secret_key[ep->last_key];
-               memset(digest, 0x00, sizeof(digest));
-               sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen,
-                                &sg, 1, digest);
+               memset(digest, 0x00, SCTP_SIGNATURE_SIZE);
+               if (crypto_hash_setkey(desc.tfm, key, keylen) ||
+                   crypto_hash_digest(&desc, &sg, bodysize, digest)) {
+                       *error = -SCTP_IERROR_NOMEM;
+                       goto fail;
+               }
 
                if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
                        /* Yikes!  Still bad signature! */
@@ -1392,11 +1423,38 @@ struct sctp_association *sctp_unpack_cookie(
        }
 
 no_hmac:
+       /* IG Section 2.35.2:
+        *  3) Compare the port numbers and the verification tag contained
+        *     within the COOKIE ECHO chunk to the actual port numbers and the
+        *     verification tag within the SCTP common header of the received
+        *     packet. If these values do not match the packet MUST be silently
+        *     discarded,
+        */
+       if (ntohl(chunk->sctp_hdr->vtag) != bear_cookie->my_vtag) {
+               *error = -SCTP_IERROR_BAD_TAG;
+               goto fail;
+       }
+
+       if (chunk->sctp_hdr->source != bear_cookie->peer_addr.v4.sin_port ||
+           ntohs(chunk->sctp_hdr->dest) != bear_cookie->my_port) {
+               *error = -SCTP_IERROR_BAD_PORTS;
+               goto fail;
+       }
+
        /* Check to see if the cookie is stale.  If there is already
         * an association, there is no need to check cookie's expiration
         * for init collision case of lost COOKIE ACK.
+        * If skb has been timestamped, then use the stamp, otherwise
+        * use current time.  This introduces a small possibility that
+        * that a cookie may be considered expired, but his would only slow
+        * down the new association establishment instead of every packet.
         */
-       if (!asoc && tv_lt(bear_cookie->expiration, skb->stamp)) {
+       if (sock_flag(ep->base.sk, SOCK_TIMESTAMP))
+               skb_get_timestamp(skb, &tv);
+       else
+               do_gettimeofday(&tv);
+
+       if (!asoc && tv_lt(bear_cookie->expiration, tv)) {
                __u16 len;
                /*
                 * Section 3.3.10.3 Stale Cookie Error (3)
@@ -1409,14 +1467,13 @@ no_hmac:
                len = ntohs(chunk->chunk_hdr->length);
                *errp = sctp_make_op_error_space(asoc, chunk, len);
                if (*errp) {
-                       suseconds_t usecs = (skb->stamp.tv_sec -
+                       suseconds_t usecs = (tv.tv_sec -
                                bear_cookie->expiration.tv_sec) * 1000000L +
-                               skb->stamp.tv_usec -
-                               bear_cookie->expiration.tv_usec;
+                               tv.tv_usec - bear_cookie->expiration.tv_usec;
+                       __be32 n = htonl(usecs);
 
-                       usecs = htonl(usecs);
                        sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE,
-                                       &usecs, sizeof(usecs));
+                                       &n, sizeof(n));
                        *error = -SCTP_IERROR_STALE_COOKIE;
                } else
                        *error = -SCTP_IERROR_NOMEM;
@@ -1446,7 +1503,7 @@ no_hmac:
 
        /* Also, add the destination address. */
        if (list_empty(&retval->base.bind_addr.address_list)) {
-               sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest,
+               sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, 1,
                                   GFP_ATOMIC);
        }
 
@@ -1455,6 +1512,7 @@ no_hmac:
        retval->addip_serial = retval->c.initial_tsn;
        retval->adv_peer_ack_point = retval->ctsn_ack_point;
        retval->peer.prsctp_capable = retval->c.prsctp_capable;
+       retval->peer.adaptation_ind = retval->c.adaptation_ind;
 
        /* The INIT stuff will be done by the side effects.  */
        return retval;
@@ -1478,8 +1536,8 @@ malformed:
  ********************************************************************/
 
 struct __sctp_missing {
-       __u32 num_missing;
-       __u16 type;
+       __be32 num_missing;
+       __be16 type;
 }  __attribute__((packed));
 
 /*
@@ -1504,7 +1562,7 @@ static int sctp_process_missing_param(const struct sctp_association *asoc,
        if (*errp) {
                report.num_missing = htonl(1);
                report.type = paramtype;
-               sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM,
+               sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM,
                                &report, sizeof(report));
        }
 
@@ -1529,6 +1587,30 @@ static int sctp_process_inv_mandatory(const struct sctp_association *asoc,
        return 0;
 }
 
+static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
+                                       struct sctp_paramhdr *param,
+                                       const struct sctp_chunk *chunk,
+                                       struct sctp_chunk **errp)
+{
+       char            error[] = "The following parameter had invalid length:";
+       size_t          payload_len = WORD_ROUND(sizeof(error)) + 
+                                               sizeof(sctp_paramhdr_t);
+
+
+       /* Create an error chunk and fill it in with our payload. */
+       if (!*errp)
+               *errp = sctp_make_op_error_space(asoc, chunk, payload_len);
+
+       if (*errp) {
+               sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, error,
+                               sizeof(error));
+               sctp_addto_chunk(*errp, sizeof(sctp_paramhdr_t), param);
+       }
+
+       return 0;
+}
+
+
 /* Do not attempt to handle the HOST_NAME parm.  However, do
  * send back an indicator to the peer.
  */
@@ -1661,6 +1743,7 @@ static int sctp_verify_param(const struct sctp_association *asoc,
        case SCTP_PARAM_HEARTBEAT_INFO:
        case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
        case SCTP_PARAM_ECN_CAPABLE:
+       case SCTP_PARAM_ADAPTATION_LAYER_IND:
                break;
 
        case SCTP_PARAM_HOST_NAME_ADDRESS:
@@ -1692,7 +1775,9 @@ int sctp_verify_init(const struct sctp_association *asoc,
 
        /* Verify stream values are non-zero. */
        if ((0 == peer_init->init_hdr.num_outbound_streams) ||
-           (0 == peer_init->init_hdr.num_inbound_streams)) {
+           (0 == peer_init->init_hdr.num_inbound_streams) ||
+           (0 == peer_init->init_hdr.init_tag) ||
+           (SCTP_DEFAULT_MINWINDOW > ntohl(peer_init->init_hdr.a_rwnd))) {
 
                sctp_process_inv_mandatory(asoc, chunk, errp);
                return 0;
@@ -1706,6 +1791,18 @@ int sctp_verify_init(const struct sctp_association *asoc,
 
        } /* for (loop through all parameters) */
 
+       /* There is a possibility that a parameter length was bad and
+        * in that case we would have stoped walking the parameters.
+        * The current param.p would point at the bad one.
+        * Current consensus on the mailing list is to generate a PROTOCOL
+        * VIOLATION error.  We build the ERROR chunk here and let the normal
+        * error handling code build and send the packet.
+        */
+       if (param.v < (void*)chunk->chunk_end - sizeof(sctp_paramhdr_t)) {
+               sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
+               return 0;
+       }
+
        /* The only missing mandatory param possible today is
         * the state cookie for an INIT-ACK chunk.
         */
@@ -1737,7 +1834,7 @@ int sctp_verify_init(const struct sctp_association *asoc,
  */
 int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
                      const union sctp_addr *peer_addr,
-                     sctp_init_chunk_t *peer_init, int gfp)
+                     sctp_init_chunk_t *peer_init, gfp_t gfp)
 {
        union sctp_params param;
        struct sctp_transport *transport;
@@ -1754,9 +1851,10 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
         * added as the primary transport.  The source address seems to
         * be a a better choice than any of the embedded addresses.
         */
-       if (peer_addr)
-               if(!sctp_assoc_add_peer(asoc, peer_addr, gfp))
+       if (peer_addr) {
+               if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE))
                        goto nomem;
+       }
 
        /* Process the initialization parameters.  */
 
@@ -1766,6 +1864,14 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
                         goto clean_up;
        }
 
+       /* Walk list of transports, removing transports in the UNKNOWN state. */
+       list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
+               transport = list_entry(pos, struct sctp_transport, transports);
+               if (transport->state == SCTP_UNKNOWN) {
+                       sctp_assoc_rm_peer(asoc, transport);
+               }
+       }
+
        /* The fixed INIT headers are always in network byte
         * order.
         */
@@ -1804,10 +1910,9 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
        /* Copy cookie in case we need to resend COOKIE-ECHO. */
        cookie = asoc->peer.cookie;
        if (cookie) {
-               asoc->peer.cookie = kmalloc(asoc->peer.cookie_len, gfp);
+               asoc->peer.cookie = kmemdup(cookie, asoc->peer.cookie_len, gfp);
                if (!asoc->peer.cookie)
                        goto clean_up;
-               memcpy(asoc->peer.cookie, cookie, asoc->peer.cookie_len);
        }
 
        /* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily
@@ -1831,7 +1936,8 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
         * stream sequence number shall be set to 0.
         */
 
-       /* Allocate storage for the negotiated streams if it is not a temporary          * association.
+       /* Allocate storage for the negotiated streams if it is not a temporary
+        * association.
         */
        if (!asoc->temp) {
                int assoc_id;
@@ -1877,6 +1983,9 @@ clean_up:
                list_del_init(pos);
                sctp_transport_free(transport);
        }
+
+       asoc->peer.transport_count = 0;
+
 nomem:
        return 0;
 }
@@ -1893,8 +2002,10 @@ nomem:
  * work we do.  In particular, we should not build transport
  * structures for the addresses.
  */
-int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
-                      const union sctp_addr *peer_addr, int gfp)
+static int sctp_process_param(struct sctp_association *asoc,
+                             union sctp_params param,
+                             const union sctp_addr *peer_addr,
+                             gfp_t gfp)
 {
        union sctp_addr addr;
        int i;
@@ -1915,10 +2026,10 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
                /* Fall through. */
        case SCTP_PARAM_IPV4_ADDRESS:
                af = sctp_get_af_specific(param_type2af(param.p->type));
-               af->from_addr_param(&addr, param.addr, asoc->peer.port, 0);
+               af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0);
                scope = sctp_scope(peer_addr);
                if (sctp_in_scope(&addr, scope))
-                       if (!sctp_assoc_add_peer(asoc, &addr, gfp))
+                       if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))
                                return 0;
                break;
 
@@ -1989,6 +2100,10 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
                asoc->peer.ecn_capable = 1;
                break;
 
+       case SCTP_PARAM_ADAPTATION_LAYER_IND:
+               asoc->peer.adaptation_ind = param.aind->adaptation_ind;
+               break;
+
        case SCTP_PARAM_FWD_TSN_SUPPORT:
                if (sctp_prsctp_enable) {
                        asoc->peer.prsctp_capable = 1;
@@ -2055,8 +2170,9 @@ __u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
  *
  * Address Parameter and other parameter will not be wrapped in this function 
  */
-struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
-                                   union sctp_addr *addr, int vparam_len)
+static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
+                                          union sctp_addr *addr,
+                                          int vparam_len)
 {
        sctp_addiphdr_t asconf;
        struct sctp_chunk *retval;
@@ -2113,7 +2229,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
                                              union sctp_addr         *laddr,
                                              struct sockaddr         *addrs,
                                              int                     addrcnt,
-                                             __u16                   flags)
+                                             __be16                  flags)
 {
        sctp_addip_param_t      param;
        struct sctp_chunk       *retval;
@@ -2225,8 +2341,8 @@ struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
  *
  * Create an ASCONF_ACK chunk with enough space for the parameter responses. 
  */
-struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
-                                       __u32 serial, int vparam_len)
+static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
+                                              __u32 serial, int vparam_len)
 {
        sctp_addiphdr_t         asconf;
        struct sctp_chunk       *retval;
@@ -2246,14 +2362,14 @@ struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
 }
 
 /* Add response parameters to an ASCONF_ACK chunk. */
-static void sctp_add_asconf_response(struct sctp_chunk *chunk, __u32 crr_id,
-                             __u16 err_code, sctp_addip_param_t *asconf_param)
+static void sctp_add_asconf_response(struct sctp_chunk *chunk, __be32 crr_id,
+                             __be16 err_code, sctp_addip_param_t *asconf_param)
 {
        sctp_addip_param_t      ack_param;
        sctp_errhdr_t           err_param;
        int                     asconf_param_len = 0;
        int                     err_param_len = 0;
-       __u16                   response_type;
+       __be16                  response_type;
 
        if (SCTP_ERROR_NO_ERROR == err_code) {
                response_type = SCTP_PARAM_SUCCESS_REPORT;
@@ -2287,7 +2403,7 @@ static void sctp_add_asconf_response(struct sctp_chunk *chunk, __u32 crr_id,
 }
 
 /* Process a asconf parameter. */
-static __u16 sctp_process_asconf_param(struct sctp_association *asoc,
+static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
                                       struct sctp_chunk *asconf,
                                       sctp_addip_param_t *asconf_param)
 {
@@ -2296,7 +2412,7 @@ static __u16 sctp_process_asconf_param(struct sctp_association *asoc,
        union sctp_addr addr;
        struct list_head *pos;
        union sctp_addr_param *addr_param;
-                                
+
        addr_param = (union sctp_addr_param *)
                        ((void *)asconf_param + sizeof(sctp_addip_param_t));
 
@@ -2304,7 +2420,7 @@ static __u16 sctp_process_asconf_param(struct sctp_association *asoc,
        if (unlikely(!af))
                return SCTP_ERROR_INV_PARAM;
 
-       af->from_addr_param(&addr, addr_param, asoc->peer.port, 0);
+       af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0);
        switch (asconf_param->param_hdr.type) {
        case SCTP_PARAM_ADD_IP:
                /* ADDIP 4.3 D9) If an endpoint receives an ADD IP address
@@ -2314,7 +2430,7 @@ static __u16 sctp_process_asconf_param(struct sctp_association *asoc,
                 * Due to Resource Shortage'.
                 */
 
-               peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC);
+               peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC, SCTP_UNCONFIRMED);
                if (!peer)
                        return SCTP_ERROR_RSRC_LOW;
 
@@ -2370,7 +2486,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
        sctp_addip_param_t      *asconf_param;
        struct sctp_chunk       *asconf_ack;
 
-       __u16   err_code;
+       __be16  err_code;
        int     length = 0;
        int     chunk_len = asconf->skb->len;
        __u32   serial;
@@ -2459,6 +2575,9 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
        union sctp_addr addr;
        struct sctp_bind_addr *bp = &asoc->base.bind_addr;
        union sctp_addr_param *addr_param;
+       struct list_head *pos;
+       struct sctp_transport *transport;
+       struct sctp_sockaddr_entry *saddr;
        int retval = 0;
 
        addr_param = (union sctp_addr_param *)
@@ -2466,13 +2585,17 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
 
        /* We have checked the packet before, so we do not check again. */
        af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type));
-       af->from_addr_param(&addr, addr_param, bp->port, 0);
+       af->from_addr_param(&addr, addr_param, htons(bp->port), 0);
 
        switch (asconf_param->param_hdr.type) {
        case SCTP_PARAM_ADD_IP:
                sctp_local_bh_disable();
                sctp_write_lock(&asoc->base.addr_lock);
-               retval = sctp_add_bind_addr(bp, &addr, GFP_ATOMIC);
+               list_for_each(pos, &bp->address_list) {
+                       saddr = list_entry(pos, struct sctp_sockaddr_entry, list);
+                       if (sctp_cmp_addr_exact(&saddr->a, &addr))
+                               saddr->use_as_src = 1;
+               }
                sctp_write_unlock(&asoc->base.addr_lock);
                sctp_local_bh_enable();
                break;
@@ -2482,6 +2605,13 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
                retval = sctp_del_bind_addr(bp, &addr);
                sctp_write_unlock(&asoc->base.addr_lock);
                sctp_local_bh_enable();
+               list_for_each(pos, &asoc->peer.transport_addr_list) {
+                       transport = list_entry(pos, struct sctp_transport,
+                                                transports);
+                       dst_release(transport->dst);
+                       sctp_transport_route(transport, NULL,
+                                            sctp_sk(asoc->base.sk));
+               }
                break;
        default:
                break;
@@ -2499,7 +2629,7 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
  * All TLVs after the failed response are considered unsuccessful unless a
  * specific success indication is present for the parameter.
  */
-static __u16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
+static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
                                      sctp_addip_param_t *asconf_param,
                                      int no_err)
 {
@@ -2507,7 +2637,7 @@ static __u16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
        sctp_errhdr_t           *err_param;
        int                     length;
        int                     asconf_ack_len = asconf_ack->skb->len;
-       __u16                   err_code;
+       __be16                  err_code;
 
        if (no_err)
                err_code = SCTP_ERROR_NO_ERROR;
@@ -2563,7 +2693,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
        int     all_param_pass = 0;
        int     no_err = 1;
        int     retval = 0;
-       __u16   err_code = SCTP_ERROR_NO_ERROR;
+       __be16  err_code = SCTP_ERROR_NO_ERROR;
 
        /* Skip the chunkhdr and addiphdr from the last asconf sent and store
         * a pointer to address parameter.
@@ -2637,8 +2767,12 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
        asoc->addip_last_asconf = NULL;
 
        /* Send the next asconf chunk from the addip chunk queue. */
-       asconf = (struct sctp_chunk *)__skb_dequeue(&asoc->addip_chunks);
-       if (asconf) {
+       if (!list_empty(&asoc->addip_chunk_list)) {
+               struct list_head *entry = asoc->addip_chunk_list.next;
+               asconf = list_entry(entry, struct sctp_chunk, list);
+
+               list_del_init(entry);
+
                /* Hold the chunk until an ASCONF_ACK is received. */
                sctp_chunk_hold(asconf);
                if (sctp_primitive_ASCONF(asoc, asconf))
@@ -2664,7 +2798,6 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
 
        hint = (nstreams + 1) * sizeof(__u32);
 
-       /* Maybe set the T-bit if we have no association.  */
        retval = sctp_make_chunk(asoc, SCTP_CID_FWD_TSN, 0, hint);
 
        if (!retval)