[SCTP]: Follow Add-IP security consideratiosn wrt INIT/INIT-ACK
[linux-3.10.git] / net / sctp / sm_statefuns.c
index 0581896..511d8c9 100644 (file)
@@ -90,8 +90,64 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
                                             const sctp_subtype_t type,
                                             void *arg,
                                             sctp_cmd_seq_t *commands);
+static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
+                                       const struct sctp_association *asoc,
+                                       const sctp_subtype_t type,
+                                       void *arg,
+                                       sctp_cmd_seq_t *commands);
 static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk);
 
+static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
+                                          __be16 error, int sk_err,
+                                          const struct sctp_association *asoc,
+                                          struct sctp_transport *transport);
+
+static sctp_disposition_t sctp_sf_abort_violation(
+                                    const struct sctp_endpoint *ep,
+                                    const struct sctp_association *asoc,
+                                    void *arg,
+                                    sctp_cmd_seq_t *commands,
+                                    const __u8 *payload,
+                                    const size_t paylen);
+
+static sctp_disposition_t sctp_sf_violation_chunklen(
+                                    const struct sctp_endpoint *ep,
+                                    const struct sctp_association *asoc,
+                                    const sctp_subtype_t type,
+                                    void *arg,
+                                    sctp_cmd_seq_t *commands);
+
+static sctp_disposition_t sctp_sf_violation_paramlen(
+                                    const struct sctp_endpoint *ep,
+                                    const struct sctp_association *asoc,
+                                    const sctp_subtype_t type,
+                                    void *arg,
+                                    sctp_cmd_seq_t *commands);
+
+static sctp_disposition_t sctp_sf_violation_ctsn(
+                                    const struct sctp_endpoint *ep,
+                                    const struct sctp_association *asoc,
+                                    const sctp_subtype_t type,
+                                    void *arg,
+                                    sctp_cmd_seq_t *commands);
+
+static sctp_disposition_t sctp_sf_violation_chunk(
+                                    const struct sctp_endpoint *ep,
+                                    const struct sctp_association *asoc,
+                                    const sctp_subtype_t type,
+                                    void *arg,
+                                    sctp_cmd_seq_t *commands);
+
+static sctp_ierror_t sctp_sf_authenticate(const struct sctp_endpoint *ep,
+                                   const struct sctp_association *asoc,
+                                   const sctp_subtype_t type,
+                                   struct sctp_chunk *chunk);
+
+static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
+                                       const struct sctp_association *asoc,
+                                       const sctp_subtype_t type,
+                                       void *arg,
+                                       sctp_cmd_seq_t *commands);
 
 /* Small helper function that checks if the chunk length
  * is of the appropriate length.  The 'required_length' argument
@@ -156,16 +212,21 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
        struct sctp_chunk *chunk = arg;
        struct sctp_ulpevent *ev;
 
+       if (!sctp_vtag_verify_either(chunk, asoc))
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
        /* RFC 2960 6.10 Bundling
         *
         * An endpoint MUST NOT bundle INIT, INIT ACK or
         * SHUTDOWN COMPLETE with any other chunks.
         */
        if (!chunk->singleton)
-               return SCTP_DISPOSITION_VIOLATION;
+               return sctp_sf_violation_chunk(ep, asoc, type, arg, commands);
 
-       if (!sctp_vtag_verify_either(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+       /* Make sure that the SHUTDOWN_COMPLETE chunk has a valid length. */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
 
        /* RFC 2960 10.2 SCTP-to-ULP
         *
@@ -175,11 +236,10 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
         * notification is passed to the upper layer.
         */
        ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP,
-                                            0, 0, 0, GFP_ATOMIC);
-       if (!ev)
-               goto nomem;
-
-       sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
+                                            0, 0, 0, NULL, GFP_ATOMIC);
+       if (ev)
+               sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+                               SCTP_ULPEVENT(ev));
 
        /* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint
         * will verify that it is in SHUTDOWN-ACK-SENT state, if it is
@@ -204,9 +264,6 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
 
        return SCTP_DISPOSITION_DELETE_TCB;
-
-nomem:
-       return SCTP_DISPOSITION_NOMEM;
 }
 
 /*
@@ -221,7 +278,7 @@ nomem:
  *    Verification Tag field to Tag_A, and also provide its own
  *    Verification Tag (Tag_Z) in the Initiate Tag field.
  *
- * Verification Tag: Must be 0. 
+ * Verification Tag: Must be 0.
  *
  * Inputs
  * (endpoint, asoc, chunk)
@@ -243,13 +300,12 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
        struct sctp_chunk *err_chunk;
        struct sctp_packet *packet;
        sctp_unrecognized_param_t *unk_param;
-       struct sock *sk;
        int len;
 
        /* 6.10 Bundling
         * An endpoint MUST NOT bundle INIT, INIT ACK or
         * SHUTDOWN COMPLETE with any other chunks.
-        * 
+        *
         * IG Section 2.11.2
         * Furthermore, we require that the receiver of an INIT chunk MUST
         * enforce these rules by silently discarding an arriving packet
@@ -264,18 +320,8 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
        if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
                return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
-       sk = ep->base.sk;
-       /* If the endpoint is not listening or if the number of associations
-        * on the TCP-style socket exceed the max backlog, respond with an
-        * ABORT.
-        */
-       if (!sctp_sstate(sk, LISTENING) ||
-           (sctp_style(sk, TCP) &&
-            sk_acceptq_is_full(sk)))
-               return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
-
        /* 3.1 A packet containing an INIT chunk MUST have a zero Verification
-        * Tag. 
+        * Tag.
         */
        if (chunk->sctp_hdr->vtag != 0)
                return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
@@ -319,7 +365,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
                }
        }
 
-        /* Grab the INIT header.  */
+       /* Grab the INIT header.  */
        chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data;
 
        /* Tag the variable length parameters.  */
@@ -336,8 +382,6 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
                               GFP_ATOMIC))
                goto nomem_init;
 
-       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
-
        /* B) "Z" shall respond immediately with an INIT ACK chunk.  */
 
        /* If there are errors need to be reported for unknown parameters,
@@ -349,11 +393,11 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
                        sizeof(sctp_chunkhdr_t);
 
        if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0)
-               goto nomem_ack;
+               goto nomem_init;
 
        repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
        if (!repl)
-               goto nomem_ack;
+               goto nomem_init;
 
        /* If there are errors need to be reported for unknown parameters,
         * include them in the outgoing INIT ACK as "Unrecognized parameter"
@@ -377,6 +421,8 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
                sctp_chunk_free(err_chunk);
        }
 
+       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
+
        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
 
        /*
@@ -389,12 +435,11 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
 
        return SCTP_DISPOSITION_DELETE_TCB;
 
-nomem_ack:
-       if (err_chunk)
-               sctp_chunk_free(err_chunk);
 nomem_init:
        sctp_association_free(new_asoc);
 nomem:
+       if (err_chunk)
+               sctp_chunk_free(err_chunk);
        return SCTP_DISPOSITION_NOMEM;
 }
 
@@ -434,58 +479,37 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
 {
        struct sctp_chunk *chunk = arg;
        sctp_init_chunk_t *initchunk;
-       __u32 init_tag;
        struct sctp_chunk *err_chunk;
        struct sctp_packet *packet;
-       sctp_disposition_t ret;
+       sctp_error_t error;
 
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-       /* Make sure that the INIT-ACK chunk has a valid length */
-       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_initack_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
-                                                 commands);
        /* 6.10 Bundling
         * An endpoint MUST NOT bundle INIT, INIT ACK or
         * SHUTDOWN COMPLETE with any other chunks.
         */
        if (!chunk->singleton)
-               return SCTP_DISPOSITION_VIOLATION;
+               return sctp_sf_violation_chunk(ep, asoc, type, arg, commands);
 
+       /* Make sure that the INIT-ACK chunk has a valid length */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_initack_chunk_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
        /* Grab the INIT header.  */
        chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
 
-       init_tag = ntohl(chunk->subh.init_hdr->init_tag);
-
-       /* Verification Tag: 3.3.3
-        *   If the value of the Initiate Tag in a received INIT ACK
-        *   chunk is found to be 0, the receiver MUST treat it as an
-        *   error and close the association by transmitting an ABORT.
-        */
-       if (!init_tag) {
-               struct sctp_chunk *reply = sctp_make_abort(asoc, chunk, 0);
-               if (!reply)
-                       goto nomem;
-
-               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
-               sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
-                               SCTP_STATE(SCTP_STATE_CLOSED));
-               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-               sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
-               return SCTP_DISPOSITION_DELETE_TCB;
-       }
-
        /* Verify the INIT chunk before processing it. */
        err_chunk = NULL;
        if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
                              (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
                              &err_chunk)) {
 
-               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-
                /* This chunk contains fatal error. It is to be discarded.
-                * Send an ABORT, with causes if there is any.
+                * Send an ABORT, with causes.  If there are no causes,
+                * then there wasn't enough memory.  Just terminate
+                * the association.
                 */
                if (err_chunk) {
                        packet = sctp_abort_pkt_new(ep, asoc, arg,
@@ -500,27 +524,29 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
                                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                                SCTP_PACKET(packet));
                                SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
-                               sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
-                                               SCTP_STATE(SCTP_STATE_CLOSED));
-                               sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB,
-                                               SCTP_NULL());
-                               return SCTP_DISPOSITION_CONSUME;
+                               error = SCTP_ERROR_INV_PARAM;
                        } else {
-                               sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
-                                               SCTP_STATE(SCTP_STATE_CLOSED));
-                               sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB,
-                                               SCTP_NULL());
-                               return SCTP_DISPOSITION_NOMEM;
+                               error = SCTP_ERROR_NO_RESOURCE;
                        }
-               } else {
-                       ret = sctp_sf_tabort_8_4_8(ep, asoc, type, arg,
-                                                  commands);
-                       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
-                                       SCTP_STATE(SCTP_STATE_CLOSED));
-                       sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB,
-                                       SCTP_NULL());
-                       return ret;
                }
+
+               /* SCTP-AUTH, Section 6.3:
+                *    It should be noted that if the receiver wants to tear
+                *    down an association in an authenticated way only, the
+                *    handling of malformed packets should not result in
+                *    tearing down the association.
+                *
+                * This means that if we only want to abort associations
+                * in an authenticated way (i.e AUTH+ABORT), then we
+                * can't destory this association just becuase the packet
+                * was malformed.
+                */
+               if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
+                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+               return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED,
+                                               asoc, chunk->transport);
        }
 
        /* Tag the variable length parameters.  Note that we never
@@ -547,6 +573,11 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_COOKIE_ECHOED));
 
+       /* SCTP-AUTH: genereate the assocition shared keys so that
+        * we can potentially signe the COOKIE-ECHO.
+        */
+       sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_SHKEY, SCTP_NULL());
+
        /* 5.1 C) "A" shall then send the State Cookie received in the
         * INIT ACK chunk in a COOKIE ECHO chunk, ...
         */
@@ -557,9 +588,6 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
                        SCTP_CHUNK(err_chunk));
 
        return SCTP_DISPOSITION_CONSUME;
-
-nomem:
-       return SCTP_DISPOSITION_NOMEM;
 }
 
 /*
@@ -602,15 +630,16 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
        struct sctp_association *new_asoc;
        sctp_init_chunk_t *peer_init;
        struct sctp_chunk *repl;
-       struct sctp_ulpevent *ev;
+       struct sctp_ulpevent *ev, *ai_ev = NULL;
        int error = 0;
        struct sctp_chunk *err_chk_p;
+       struct sock *sk;
 
        /* If the packet is an OOTB packet which is temporarily on the
         * control endpoint, respond with an ABORT.
         */
        if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
-               return sctp_sf_ootb(ep, asoc, type, arg, commands);
+               return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
        /* Make sure that the COOKIE_ECHO chunk has a valid length.
         * In this case, we check that we have enough for at least a
@@ -620,13 +649,23 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* If the endpoint is not listening or if the number of associations
+        * on the TCP-style socket exceed the max backlog, respond with an
+        * ABORT.
+        */
+       sk = ep->base.sk;
+       if (!sctp_sstate(sk, LISTENING) ||
+           (sctp_style(sk, TCP) && sk_acceptq_is_full(sk)))
+               return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+
        /* "Decode" the chunk.  We have no optional parameters so we
         * are in good shape.
         */
-        chunk->subh.cookie_hdr =
+       chunk->subh.cookie_hdr =
                (struct sctp_signed_cookie *)chunk->skb->data;
-       skb_pull(chunk->skb,
-                ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t));
+       if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
+                                        sizeof(sctp_chunkhdr_t)))
+               goto nomem;
 
        /* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint
         * "Z" will reply with a COOKIE ACK chunk after building a TCB
@@ -657,23 +696,13 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
                case -SCTP_IERROR_BAD_SIG:
                default:
                        return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-               };
+               }
        }
 
-       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
-       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
-                       SCTP_STATE(SCTP_STATE_ESTABLISHED));
-       SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
-       SCTP_INC_STATS(SCTP_MIB_PASSIVEESTABS);
-       sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
 
-       if (new_asoc->autoclose)
-               sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
-                               SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
-
-       sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
-
-       /* Re-build the bind address for the association is done in
+       /* Delay state machine commands until later.
+        *
+        * Re-build the bind address for the association is done in
         * the sctp_unpack_cookie() already.
         */
        /* This is a brand-new association, so these are not yet side
@@ -686,11 +715,47 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
                               peer_init, GFP_ATOMIC))
                goto nomem_init;
 
+       /* SCTP-AUTH:  Now that we've populate required fields in
+        * sctp_process_init, set up the assocaition shared keys as
+        * necessary so that we can potentially authenticate the ACK
+        */
+       error = sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC);
+       if (error)
+               goto nomem_init;
+
+       /* SCTP-AUTH:  auth_chunk pointer is only set when the cookie-echo
+        * is supposed to be authenticated and we have to do delayed
+        * authentication.  We've just recreated the association using
+        * the information in the cookie and now it's much easier to
+        * do the authentication.
+        */
+       if (chunk->auth_chunk) {
+               struct sctp_chunk auth;
+               sctp_ierror_t ret;
+
+               /* set-up our fake chunk so that we can process it */
+               auth.skb = chunk->auth_chunk;
+               auth.asoc = chunk->asoc;
+               auth.sctp_hdr = chunk->sctp_hdr;
+               auth.chunk_hdr = (sctp_chunkhdr_t *)skb_push(chunk->auth_chunk,
+                                           sizeof(sctp_chunkhdr_t));
+               skb_pull(chunk->auth_chunk, sizeof(sctp_chunkhdr_t));
+               auth.transport = chunk->transport;
+
+               ret = sctp_sf_authenticate(ep, new_asoc, type, &auth);
+
+               /* We can now safely free the auth_chunk clone */
+               kfree_skb(chunk->auth_chunk);
+
+               if (ret != SCTP_IERROR_NO_ERROR) {
+                       sctp_association_free(new_asoc);
+                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               }
+       }
+
        repl = sctp_make_cookie_ack(new_asoc, chunk);
        if (!repl)
-               goto nomem_repl;
-
-       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
+               goto nomem_init;
 
        /* RFC 2960 5.1 Normal Establishment of an Association
         *
@@ -701,32 +766,57 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
        ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, SCTP_COMM_UP, 0,
                                             new_asoc->c.sinit_num_ostreams,
                                             new_asoc->c.sinit_max_instreams,
-                                            GFP_ATOMIC);
+                                            NULL, GFP_ATOMIC);
        if (!ev)
                goto nomem_ev;
 
-       sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
-
-       /* Sockets API Draft Section 5.3.1.6    
-        * When a peer sends a Adaption Layer Indication parameter , SCTP
+       /* Sockets API Draft Section 5.3.1.6
+        * When a peer sends a Adaptation Layer Indication parameter , SCTP
         * delivers this notification to inform the application that of the
-        * peers requested adaption layer.
+        * peers requested adaptation layer.
         */
-       if (new_asoc->peer.adaption_ind) {
-               ev = sctp_ulpevent_make_adaption_indication(new_asoc,
+       if (new_asoc->peer.adaptation_ind) {
+               ai_ev = sctp_ulpevent_make_adaptation_indication(new_asoc,
                                                            GFP_ATOMIC);
-               if (!ev)
-                       goto nomem_ev;
+               if (!ai_ev)
+                       goto nomem_aiev;
+       }
+
+       /* Add all the state machine commands now since we've created
+        * everything.  This way we don't introduce memory corruptions
+        * during side-effect processing and correclty count established
+        * associations.
+        */
+       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
+       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
+                       SCTP_STATE(SCTP_STATE_ESTABLISHED));
+       SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
+       SCTP_INC_STATS(SCTP_MIB_PASSIVEESTABS);
+       sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
+
+       if (new_asoc->autoclose)
+               sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
+                               SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
+
+       sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
+
+       /* This will send the COOKIE ACK */
+       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
 
+       /* Queue the ASSOC_CHANGE event */
+       sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
+
+       /* Send up the Adaptation Layer Indication event */
+       if (ai_ev)
                sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
-                               SCTP_ULPEVENT(ev));
-       }
+                               SCTP_ULPEVENT(ai_ev));
 
        return SCTP_DISPOSITION_CONSUME;
 
+nomem_aiev:
+       sctp_ulpevent_free(ev);
 nomem_ev:
        sctp_chunk_free(repl);
-nomem_repl:
 nomem_init:
        sctp_association_free(new_asoc);
 nomem:
@@ -805,7 +895,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
        ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP,
                                             0, asoc->c.sinit_num_ostreams,
                                             asoc->c.sinit_max_instreams,
-                                            GFP_ATOMIC);
+                                            NULL, GFP_ATOMIC);
 
        if (!ev)
                goto nomem;
@@ -813,12 +903,12 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
 
        /* Sockets API Draft Section 5.3.1.6
-        * When a peer sends a Adaption Layer Indication parameter , SCTP
+        * When a peer sends a Adaptation Layer Indication parameter , SCTP
         * delivers this notification to inform the application that of the
-        * peers requested adaption layer.
+        * peers requested adaptation layer.
         */
-       if (asoc->peer.adaption_ind) {
-               ev = sctp_ulpevent_make_adaption_indication(asoc, GFP_ATOMIC);
+       if (asoc->peer.adaptation_ind) {
+               ev = sctp_ulpevent_make_adaptation_indication(asoc, GFP_ATOMIC);
                if (!ev)
                        goto nomem;
 
@@ -847,6 +937,7 @@ static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
        hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t));
        hbinfo.daddr = transport->ipaddr;
        hbinfo.sent_at = jiffies;
+       hbinfo.hb_nonce = transport->hb_nonce;
 
        /* Send a heartbeat to our peer.  */
        paylen = sizeof(sctp_sender_hb_info_t);
@@ -874,9 +965,11 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
        struct sctp_transport *transport = (struct sctp_transport *) arg;
 
        if (asoc->overall_error_count > asoc->max_retrans) {
+               sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                               SCTP_ERROR(ETIMEDOUT));
                /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-                               SCTP_U32(SCTP_ERROR_NO_ERROR));
+                               SCTP_PERR(SCTP_ERROR_NO_ERROR));
                SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
                SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_DELETE_TCB;
@@ -889,7 +982,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
         * HEARTBEAT is sent (see Section 8.3).
         */
 
-       if (transport->hb_allowed) {
+       if (transport->param_flags & SPP_HB_ENABLE) {
                if (SCTP_DISPOSITION_NOMEM ==
                                sctp_sf_heartbeat(ep, asoc, type, arg,
                                                  commands))
@@ -903,7 +996,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMER_UPDATE,
                        SCTP_TRANSPORT(transport));
 
-        return SCTP_DISPOSITION_CONSUME;
+       return SCTP_DISPOSITION_CONSUME;
 }
 
 /*
@@ -954,7 +1047,8 @@ sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep,
         */
        chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data;
        paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t);
-       skb_pull(chunk->skb, paylen);
+       if (!pskb_pull(chunk->skb, paylen))
+               goto nomem;
 
        reply = sctp_make_heartbeat_ack(asoc, chunk,
                                        chunk->subh.hb_hdr, paylen);
@@ -1017,35 +1111,47 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
                                                  commands);
 
        hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;
+       /* Make sure that the length of the parameter is what we expect */
+       if (ntohs(hbinfo->param_hdr.length) !=
+                                   sizeof(sctp_sender_hb_info_t)) {
+               return SCTP_DISPOSITION_DISCARD;
+       }
+
        from_addr = hbinfo->daddr;
        link = sctp_assoc_lookup_paddr(asoc, &from_addr);
 
        /* This should never happen, but lets log it if so.  */
        if (unlikely(!link)) {
                if (from_addr.sa.sa_family == AF_INET6) {
-                       printk(KERN_WARNING
-                              "%s association %p could not find address "
-                              "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-                              __FUNCTION__,
-                              asoc,
-                              NIP6(from_addr.v6.sin6_addr));
+                       if (net_ratelimit())
+                               printk(KERN_WARNING
+                                   "%s association %p could not find address "
+                                   NIP6_FMT "\n",
+                                   __FUNCTION__,
+                                   asoc,
+                                   NIP6(from_addr.v6.sin6_addr));
                } else {
-                       printk(KERN_WARNING
-                              "%s association %p could not find address "
-                              "%u.%u.%u.%u\n",
-                              __FUNCTION__,
-                              asoc,
-                              NIPQUAD(from_addr.v4.sin_addr.s_addr));
+                       if (net_ratelimit())
+                               printk(KERN_WARNING
+                                   "%s association %p could not find address "
+                                   NIPQUAD_FMT "\n",
+                                   __FUNCTION__,
+                                   asoc,
+                                   NIPQUAD(from_addr.v4.sin_addr.s_addr));
                }
                return SCTP_DISPOSITION_DISCARD;
        }
 
-       max_interval = link->hb_interval + link->rto;
+       /* Validate the 64-bit random nonce. */
+       if (hbinfo->hb_nonce != link->hb_nonce)
+               return SCTP_DISPOSITION_DISCARD;
+
+       max_interval = link->hbinterval + link->rto;
 
        /* Check if the timestamp looks valid.  */
        if (time_after(hbinfo->sent_at, jiffies) ||
            time_after(jiffies, hbinfo->sent_at + max_interval)) {
-               SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp"
+               SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp "
                                  "received for transport: %p\n",
                                   __FUNCTION__, link);
                return SCTP_DISPOSITION_DISCARD;
@@ -1196,7 +1302,7 @@ static void sctp_tietags_populate(struct sctp_association *new_asoc,
                new_asoc->c.my_ttag   = asoc->c.my_vtag;
                new_asoc->c.peer_ttag = asoc->c.peer_vtag;
                break;
-       };
+       }
 
        /* Other parameters for the endpoint SHOULD be copied from the
         * existing parameters of the association (e.g. number of
@@ -1281,7 +1387,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
        /* 3.1 A packet containing an INIT chunk MUST have a zero Verification
-        * Tag. 
+        * Tag.
         */
        if (chunk->sctp_hdr->vtag != 0)
                return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
@@ -1347,10 +1453,8 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
        if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
                               sctp_source(chunk),
                               (sctp_init_chunk_t *)chunk->chunk_hdr,
-                              GFP_ATOMIC)) {
-               retval = SCTP_DISPOSITION_NOMEM;
-               goto nomem_init;
-       }
+                              GFP_ATOMIC))
+               goto nomem;
 
        /* Make sure no new addresses are being added during the
         * restart.   Do not do this check for COOKIE-WAIT state,
@@ -1361,7 +1465,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
                if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk,
                                                 commands)) {
                        retval = SCTP_DISPOSITION_CONSUME;
-                       goto cleanup_asoc;
+                       goto nomem_retval;
                }
        }
 
@@ -1417,17 +1521,17 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
        sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
        retval = SCTP_DISPOSITION_CONSUME;
 
+       return retval;
+
+nomem:
+       retval = SCTP_DISPOSITION_NOMEM;
+nomem_retval:
+       if (new_asoc)
+               sctp_association_free(new_asoc);
 cleanup:
        if (err_chunk)
                sctp_chunk_free(err_chunk);
        return retval;
-nomem:
-       retval = SCTP_DISPOSITION_NOMEM;
-       goto cleanup;
-nomem_init:
-cleanup_asoc:
-       sctp_association_free(new_asoc);
-       goto cleanup;
 }
 
 /*
@@ -1534,6 +1638,28 @@ sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const struct sctp_endpoint *ep,
 }
 
 
+/*
+ * Unexpected INIT-ACK handler.
+ *
+ * Section 5.2.3
+ * If an INIT ACK received by an endpoint in any state other than the
+ * COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk.
+ * An unexpected INIT ACK usually indicates the processing of an old or
+ * duplicated INIT chunk.
+*/
+sctp_disposition_t sctp_sf_do_5_2_3_initack(const struct sctp_endpoint *ep,
+                                           const struct sctp_association *asoc,
+                                           const sctp_subtype_t type,
+                                           void *arg, sctp_cmd_seq_t *commands)
+{
+       /* Per the above section, we'll discard the chunk if we have an
+        * endpoint.  If this is an OOTB INIT-ACK, treat it as such.
+        */
+       if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
+               return sctp_sf_ootb(ep, asoc, type, arg, commands);
+       else
+               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+}
 
 /* Unexpected COOKIE-ECHO handler for peer restart (Table 2, action 'A')
  *
@@ -1598,23 +1724,21 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep,
         */
        sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL());
 
-       /* Update the content of current association. */
-       sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
-
        repl = sctp_make_cookie_ack(new_asoc, chunk);
        if (!repl)
                goto nomem;
 
-       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
-
        /* Report association restart to upper layer. */
        ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0,
                                             new_asoc->c.sinit_num_ostreams,
                                             new_asoc->c.sinit_max_instreams,
-                                            GFP_ATOMIC);
+                                            NULL, GFP_ATOMIC);
        if (!ev)
                goto nomem_ev;
 
+       /* Update the content of current association. */
+       sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
+       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
        sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
        return SCTP_DISPOSITION_CONSUME;
 
@@ -1639,7 +1763,6 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
                                        struct sctp_association *new_asoc)
 {
        sctp_init_chunk_t *peer_init;
-       struct sctp_ulpevent *ev;
        struct sctp_chunk *repl;
 
        /* new_asoc is a brand-new association, so these are not yet
@@ -1670,34 +1793,28 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
         * D) IMPLEMENTATION NOTE: An implementation may choose to
         * send the Communication Up notification to the SCTP user
         * upon reception of a valid COOKIE ECHO chunk.
+        *
+        * Sadly, this needs to be implemented as a side-effect, because
+        * we are not guaranteed to have set the association id of the real
+        * association and so these notifications need to be delayed until
+        * the association id is allocated.
         */
-       ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0,
-                                            new_asoc->c.sinit_num_ostreams,
-                                            new_asoc->c.sinit_max_instreams,
-                                            GFP_ATOMIC);
-       if (!ev)
-               goto nomem_ev;
 
-       sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
+       sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_CHANGE, SCTP_U8(SCTP_COMM_UP));
 
        /* Sockets API Draft Section 5.3.1.6
-        * When a peer sends a Adaption Layer Indication parameter , SCTP
+        * When a peer sends a Adaptation Layer Indication parameter , SCTP
         * delivers this notification to inform the application that of the
-        * peers requested adaption layer.
+        * peers requested adaptation layer.
+        *
+        * This also needs to be done as a side effect for the same reason as
+        * above.
         */
-       if (asoc->peer.adaption_ind) {
-               ev = sctp_ulpevent_make_adaption_indication(asoc, GFP_ATOMIC);
-               if (!ev)
-                       goto nomem_ev;
-
-               sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
-                               SCTP_ULPEVENT(ev));
-       }
+       if (asoc->peer.adaptation_ind)
+               sctp_add_cmd_sf(commands, SCTP_CMD_ADAPTATION_IND, SCTP_NULL());
 
        return SCTP_DISPOSITION_CONSUME;
 
-nomem_ev:
-       sctp_chunk_free(repl);
 nomem:
        return SCTP_DISPOSITION_NOMEM;
 }
@@ -1738,14 +1855,14 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
                                        sctp_cmd_seq_t *commands,
                                        struct sctp_association *new_asoc)
 {
-       struct sctp_ulpevent *ev = NULL;
+       struct sctp_ulpevent *ev = NULL, *ai_ev = NULL;
        struct sctp_chunk *repl;
 
        /* Clarification from Implementor's Guide:
         * D) When both local and remote tags match the endpoint should
-         * enter the ESTABLISHED state, if it is in the COOKIE-ECHOED state.
-         * It should stop any cookie timer that may be running and send
-         * a COOKIE ACK.
+        * enter the ESTABLISHED state, if it is in the COOKIE-ECHOED state.
+        * It should stop any cookie timer that may be running and send
+        * a COOKIE ACK.
         */
 
        /* Don't accidentally move back into established state. */
@@ -1765,29 +1882,25 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
                 * SCTP user upon reception of a valid COOKIE
                 * ECHO chunk.
                 */
-               ev = sctp_ulpevent_make_assoc_change(new_asoc, 0,
+               ev = sctp_ulpevent_make_assoc_change(asoc, 0,
                                             SCTP_COMM_UP, 0,
-                                            new_asoc->c.sinit_num_ostreams,
-                                            new_asoc->c.sinit_max_instreams,
-                                             GFP_ATOMIC);
+                                            asoc->c.sinit_num_ostreams,
+                                            asoc->c.sinit_max_instreams,
+                                            NULL, GFP_ATOMIC);
                if (!ev)
                        goto nomem;
-               sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
-                               SCTP_ULPEVENT(ev));
 
                /* Sockets API Draft Section 5.3.1.6
-                * When a peer sends a Adaption Layer Indication parameter,
+                * When a peer sends a Adaptation Layer Indication parameter,
                 * SCTP delivers this notification to inform the application
-                * that of the peers requested adaption layer.
+                * that of the peers requested adaptation layer.
                 */
-               if (new_asoc->peer.adaption_ind) {
-                       ev = sctp_ulpevent_make_adaption_indication(new_asoc,
+               if (asoc->peer.adaptation_ind) {
+                       ai_ev = sctp_ulpevent_make_adaptation_indication(asoc,
                                                                 GFP_ATOMIC);
-                       if (!ev)
+                       if (!ai_ev)
                                goto nomem;
 
-                       sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
-                                       SCTP_ULPEVENT(ev));
                }
        }
        sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
@@ -1796,12 +1909,21 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
        if (!repl)
                goto nomem;
 
+       if (ev)
+               sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+                               SCTP_ULPEVENT(ev));
+       if (ai_ev)
+               sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+                                       SCTP_ULPEVENT(ai_ev));
+
        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
        sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
 
        return SCTP_DISPOSITION_CONSUME;
 
 nomem:
+       if (ai_ev)
+               sctp_ulpevent_free(ai_ev);
        if (ev)
                sctp_ulpevent_free(ev);
        return SCTP_DISPOSITION_NOMEM;
@@ -1848,9 +1970,10 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
        /* "Decode" the chunk.  We have no optional parameters so we
         * are in good shape.
         */
-        chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data;
-       skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
-                sizeof(sctp_chunkhdr_t));
+       chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data;
+       if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
+                                       sizeof(sctp_chunkhdr_t)))
+               goto nomem;
 
        /* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie
         * of a duplicate COOKIE ECHO match the Verification Tags of the
@@ -1881,7 +2004,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
                case -SCTP_IERROR_BAD_SIG:
                default:
                        return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-               };
+               }
        }
 
        /* Compare the tie_tag in cookie with the verification tag of
@@ -1913,7 +2036,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
        default: /* Discard packet for all others. */
                retval = sctp_sf_pdiscard(ep, asoc, type, arg, commands);
                break;
-        };
+       }
 
        /* Delete the tempory new association. */
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
@@ -1955,11 +2078,20 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* ADD-IP: Special case for ABORT chunks
+        * F4)  One special consideration is that ABORT Chunks arriving
+        * destined to the IP address being deleted MUST be
+        * ignored (see Section 5.3.1 for further details).
+        */
+       if (SCTP_ADDR_DEL ==
+                   sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
+               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+
        /* Stop the T5-shutdown guard timer.  */
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
 
-       return sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
+       return __sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
 }
 
 /*
@@ -1991,6 +2123,15 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* ADD-IP: Special case for ABORT chunks
+        * F4)  One special consideration is that ABORT Chunks arriving
+        * destined to the IP address being deleted MUST be
+        * ignored (see Section 5.3.1 for further details).
+        */
+       if (SCTP_ADDR_DEL ==
+                   sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
+               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+
        /* Stop the T2-shutdown timer. */
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
@@ -1999,7 +2140,7 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
 
-       return sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
+       return __sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
 }
 
 /*
@@ -2060,7 +2201,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
         */
        sctp_walk_errors(err, chunk->chunk_hdr) {
                if (SCTP_ERROR_STALE_COOKIE == err->cause)
-                       return sctp_sf_do_5_2_6_stale(ep, asoc, type, 
+                       return sctp_sf_do_5_2_6_stale(ep, asoc, type,
                                                        arg, commands);
        }
 
@@ -2111,9 +2252,11 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
        struct sctp_bind_addr *bp;
        int attempts = asoc->init_err_counter + 1;
 
-       if (attempts >= asoc->max_init_attempts) {
+       if (attempts > asoc->max_init_attempts) {
+               sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                               SCTP_ERROR(ETIMEDOUT));
                sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
-                               SCTP_U32(SCTP_ERROR_STALE_COOKIE));
+                               SCTP_PERR(SCTP_ERROR_STALE_COOKIE));
                return SCTP_DISPOSITION_DELETE_TCB;
        }
 
@@ -2133,7 +2276,7 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
         * to give ample time to retransmit the new cookie and thus
         * yield a higher probability of success on the reattempt.
         */
-       stale = ntohl(*(suseconds_t *)((u8 *)err + sizeof(sctp_errhdr_t)));
+       stale = ntohl(*(__be32 *)((u8 *)err + sizeof(sctp_errhdr_t)));
        stale = (stale * 2) / 1000;
 
        bht.param_hdr.type = SCTP_PARAM_COOKIE_PRESERVATIVE;
@@ -2160,10 +2303,10 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
         */
        sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL());
 
-       /* If we've sent any data bundled with COOKIE-ECHO we will need to 
-        * resend 
+       /* If we've sent any data bundled with COOKIE-ECHO we will need to
+        * resend
         */
-       sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, 
+       sctp_add_cmd_sf(commands, SCTP_CMD_T1_RETRAN,
                        SCTP_TRANSPORT(asoc->peer.primary_path));
 
        /* Cast away the const modifier, as we want to just
@@ -2224,8 +2367,6 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
                                        sctp_cmd_seq_t *commands)
 {
        struct sctp_chunk *chunk = arg;
-       unsigned len;
-       __u16 error = SCTP_ERROR_NO_ERROR;
 
        if (!sctp_vtag_verify_either(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
@@ -2243,13 +2384,36 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* ADD-IP: Special case for ABORT chunks
+        * F4)  One special consideration is that ABORT Chunks arriving
+        * destined to the IP address being deleted MUST be
+        * ignored (see Section 5.3.1 for further details).
+        */
+       if (SCTP_ADDR_DEL ==
+                   sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
+               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+
+       return __sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
+}
+
+static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
+                                       const struct sctp_association *asoc,
+                                       const sctp_subtype_t type,
+                                       void *arg,
+                                       sctp_cmd_seq_t *commands)
+{
+       struct sctp_chunk *chunk = arg;
+       unsigned len;
+       __be16 error = SCTP_ERROR_NO_ERROR;
+
        /* See if we have an error cause code in the chunk.  */
        len = ntohs(chunk->chunk_hdr->length);
        if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
                error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
 
-       /* ASSOC_FAILED will DELETE_TCB. */
-       sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(error));
+       sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNRESET));
+       /* ASSOC_FAILED will DELETE_TCB. */
+       sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_PERR(error));
        SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
        SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
 
@@ -2269,7 +2433,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
 {
        struct sctp_chunk *chunk = arg;
        unsigned len;
-       __u16 error = SCTP_ERROR_NO_ERROR;
+       __be16 error = SCTP_ERROR_NO_ERROR;
 
        if (!sctp_vtag_verify_either(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
@@ -2292,7 +2456,8 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
        if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
                error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
 
-       return sctp_stop_t1_and_abort(commands, error, asoc, chunk->transport);
+       return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED, asoc,
+                                     chunk->transport);
 }
 
 /*
@@ -2304,7 +2469,8 @@ sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(const struct sctp_endpoint *ep
                                        void *arg,
                                        sctp_cmd_seq_t *commands)
 {
-       return sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR, asoc,
+       return sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR,
+                                     ENOPROTOOPT, asoc,
                                      (struct sctp_transport *)arg);
 }
 
@@ -2328,8 +2494,8 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
  *
  * This is common code called by several sctp_sf_*_abort() functions above.
  */
-sctp_disposition_t  sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
-                                          __u16 error,
+static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
+                                          __be16 error, int sk_err,
                                           const struct sctp_association *asoc,
                                           struct sctp_transport *transport)
 {
@@ -2339,9 +2505,10 @@ sctp_disposition_t  sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
        SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+       sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(sk_err));
        /* CMD_INIT_FAILED will DELETE_TCB. */
        sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
-                       SCTP_U32(error));
+                       SCTP_PERR(error));
        return SCTP_DISPOSITION_ABORT;
 }
 
@@ -2403,6 +2570,17 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
        skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t));
        chunk->subh.shutdown_hdr = sdh;
 
+       /* API 5.3.1.5 SCTP_SHUTDOWN_EVENT
+        * When a peer sends a SHUTDOWN, SCTP delivers this notification to
+        * inform the application that it should cease sending data.
+        */
+       ev = sctp_ulpevent_make_shutdown_event(asoc, 0, GFP_ATOMIC);
+       if (!ev) {
+               disposition = SCTP_DISPOSITION_NOMEM;
+               goto out;
+       }
+       sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
+
        /* Upon the reception of the SHUTDOWN, the peer endpoint shall
         *  - enter the SHUTDOWN-RECEIVED state,
         *  - stop accepting new data from its SCTP user
@@ -2426,18 +2604,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
         *    received by the SHUTDOWN sender.
         */
        sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_CTSN,
-                       SCTP_U32(chunk->subh.shutdown_hdr->cum_tsn_ack));
-
-       /* API 5.3.1.5 SCTP_SHUTDOWN_EVENT
-        * When a peer sends a SHUTDOWN, SCTP delivers this notification to
-        * inform the application that it should cease sending data.
-        */
-       ev = sctp_ulpevent_make_shutdown_event(asoc, 0, GFP_ATOMIC);
-       if (!ev) {
-               disposition = SCTP_DISPOSITION_NOMEM;
-               goto out;       
-       }
-       sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
+                       SCTP_BE32(chunk->subh.shutdown_hdr->cum_tsn_ack));
 
 out:
        return disposition;
@@ -2459,6 +2626,11 @@ sctp_disposition_t sctp_sf_do_9_2_reshutack(const struct sctp_endpoint *ep,
        struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
        struct sctp_chunk *reply;
 
+       /* Make sure that the chunk has a valid length */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        /* Since we are not going to really process this INIT, there
         * is no point in verifying chunk boundries.  Just generate
         * the SHUTDOWN ACK.
@@ -2516,6 +2688,7 @@ sctp_disposition_t sctp_sf_do_ecn_cwr(const struct sctp_endpoint *ep,
 {
        sctp_cwrhdr_t *cwr;
        struct sctp_chunk *chunk = arg;
+       u32 lowest_tsn;
 
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
@@ -2523,18 +2696,18 @@ sctp_disposition_t sctp_sf_do_ecn_cwr(const struct sctp_endpoint *ep,
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_ecne_chunk_t)))
                return sctp_sf_violation_chunklen(ep, asoc, type, arg,
                                                  commands);
-               
+
        cwr = (sctp_cwrhdr_t *) chunk->skb->data;
        skb_pull(chunk->skb, sizeof(sctp_cwrhdr_t));
 
-       cwr->lowest_tsn = ntohl(cwr->lowest_tsn);
+       lowest_tsn = ntohl(cwr->lowest_tsn);
 
        /* Does this CWR ack the last sent congestion notification? */
-       if (TSN_lte(asoc->last_ecne_tsn, cwr->lowest_tsn)) {
+       if (TSN_lte(asoc->last_ecne_tsn, lowest_tsn)) {
                /* Stop sending ECNE. */
                sctp_add_cmd_sf(commands,
                                SCTP_CMD_ECN_CWR,
-                               SCTP_U32(cwr->lowest_tsn));
+                               SCTP_U32(lowest_tsn));
        }
        return SCTP_DISPOSITION_CONSUME;
 }
@@ -2631,7 +2804,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
                                SCTP_NULL());
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-        }
+       }
 
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t)))
                return sctp_sf_violation_chunklen(ep, asoc, type, arg,
@@ -2643,9 +2816,11 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
                break;
        case SCTP_IERROR_HIGH_TSN:
        case SCTP_IERROR_BAD_STREAM:
+               SCTP_INC_STATS(SCTP_MIB_IN_DATA_CHUNK_DISCARDS);
                goto discard_noforce;
        case SCTP_IERROR_DUP_TSN:
        case SCTP_IERROR_IGNORE_TSN:
+               SCTP_INC_STATS(SCTP_MIB_IN_DATA_CHUNK_DISCARDS);
                goto discard_force;
        case SCTP_IERROR_NO_DATA:
                goto consume;
@@ -2680,14 +2855,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
         * document allow. However, an SCTP transmitter MUST NOT be
         * more aggressive than the following algorithms allow.
         */
-       if (chunk->end_of_packet) {
+       if (chunk->end_of_packet)
                sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE());
 
-               /* Start the SACK timer.  */
-               sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
-                               SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
-       }
-
        return SCTP_DISPOSITION_CONSUME;
 
 discard_force:
@@ -2710,17 +2880,13 @@ discard_force:
        return SCTP_DISPOSITION_DISCARD;
 
 discard_noforce:
-       if (chunk->end_of_packet) {
+       if (chunk->end_of_packet)
                sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE());
 
-               /* Start the SACK timer.  */
-               sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
-                               SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
-       }
        return SCTP_DISPOSITION_DISCARD;
 consume:
        return SCTP_DISPOSITION_CONSUME;
-       
+
 }
 
 /*
@@ -2864,6 +3030,13 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
                return SCTP_DISPOSITION_DISCARD;
        }
 
+       /* If Cumulative TSN Ack beyond the max tsn currently
+        * send, terminating the association and respond to the
+        * sender with an ABORT.
+        */
+       if (!TSN_lt(ctsn, asoc->next_tsn))
+               return sctp_sf_violation_ctsn(ep, asoc, type, arg, commands);
+
        /* Return this SACK for further processing.  */
        sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, SCTP_SACKH(sackh));
 
@@ -2891,7 +3064,7 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
 */
-sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -2907,7 +3080,7 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
                /* Make an ABORT. The T bit will be set if the asoc
                 * is NULL.
                 */
-               abort = sctp_make_abort(asoc, chunk, 0);
+               abort = sctp_make_abort(asoc, chunk, 0);
                if (!abort) {
                        sctp_ootb_pkt_free(packet);
                        return SCTP_DISPOSITION_NOMEM;
@@ -2927,6 +3100,7 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
 
                SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
 
+               sctp_sf_pdiscard(ep, asoc, type, arg, commands);
                return SCTP_DISPOSITION_CONSUME;
        }
 
@@ -2971,7 +3145,7 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
                }
 
                sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR,
-                               SCTP_CHUNK(chunk));     
+                               SCTP_CHUNK(chunk));
        }
        return SCTP_DISPOSITION_CONSUME;
 
@@ -3006,17 +3180,24 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
                return sctp_sf_violation_chunklen(ep, asoc, type, arg,
                                                  commands);
-
        /* 10.2 H) SHUTDOWN COMPLETE notification
         *
         * When SCTP completes the shutdown procedures (section 9.2) this
         * notification is passed to the upper layer.
         */
        ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP,
-                                            0, 0, 0, GFP_ATOMIC);
+                                            0, 0, 0, NULL, GFP_ATOMIC);
        if (!ev)
                goto nomem;
 
+       /* ...send a SHUTDOWN COMPLETE chunk to its peer, */
+       reply = sctp_make_shutdown_complete(asoc, chunk);
+       if (!reply)
+               goto nomem_chunk;
+
+       /* Do all the commands now (after allocation), so that we
+        * have consistent state if memory allocation failes
+        */
        sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
 
        /* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall
@@ -3028,11 +3209,6 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
 
-       /* ...send a SHUTDOWN COMPLETE chunk to its peer, */
-       reply = sctp_make_shutdown_complete(asoc, chunk);
-       if (!reply)
-               goto nomem;
-
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
        SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS);
@@ -3043,6 +3219,8 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
        return SCTP_DISPOSITION_DELETE_TCB;
 
+nomem_chunk:
+       sctp_ulpevent_free(ev);
 nomem:
        return SCTP_DISPOSITION_NOMEM;
 }
@@ -3083,12 +3261,14 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
 
        ch = (sctp_chunkhdr_t *) chunk->chunk_hdr;
        do {
-               /* Break out if chunk length is less then minimal. */
+               /* Report violation if the chunk is less then minimal */
                if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
-                       break;
-
-               ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+                       return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
 
+               /* Now that we know we at least have a chunk header,
+                * do things that are type appropriate.
+                */
                if (SCTP_CID_SHUTDOWN_ACK == ch->type)
                        ootb_shut_ack = 1;
 
@@ -3099,16 +3279,20 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
                 */
                if (SCTP_CID_ABORT == ch->type)
                        return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-                       
+
+               /* Report violation if chunk len overflows */
+               ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+               if (ch_end > skb_tail_pointer(skb))
+                       return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
                ch = (sctp_chunkhdr_t *) ch_end;
-       } while (ch_end < skb->tail);
+       } while (ch_end < skb_tail_pointer(skb));
 
        if (ootb_shut_ack)
-               sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands);
+               return sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands);
        else
-               sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
-
-       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 }
 
 /*
@@ -3146,8 +3330,8 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
 
        if (packet) {
                /* Make an SHUTDOWN_COMPLETE.
-                * The T bit will be set if the asoc is NULL.
-                */
+                * The T bit will be set if the asoc is NULL.
+                */
                shut = sctp_make_shutdown_complete(asoc, chunk);
                if (!shut) {
                        sctp_ootb_pkt_free(packet);
@@ -3174,7 +3358,11 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
                if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
                        return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-               return SCTP_DISPOSITION_CONSUME;
+               /* We need to discard the rest of the packet to prevent
+                * potential bomming attacks from additional bundled chunks.
+                * This is documented in SCTP Threats ID.
+                */
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
        }
 
        return SCTP_DISPOSITION_NOMEM;
@@ -3197,6 +3385,13 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep,
                                      void *arg,
                                      sctp_cmd_seq_t *commands)
 {
+       struct sctp_chunk *chunk = arg;
+
+       /* Make sure that the SHUTDOWN_ACK chunk has a valid length. */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        /* Although we do have an association in this case, it corresponds
         * to a restarted association. So the packet is treated as an OOTB
         * packet and the state function that handles OOTB SHUTDOWN_ACK is
@@ -3213,8 +3408,11 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
 {
        struct sctp_chunk       *chunk = arg;
        struct sctp_chunk       *asconf_ack = NULL;
+       struct sctp_paramhdr    *err_param = NULL;
        sctp_addiphdr_t         *hdr;
+       union sctp_addr_param   *addr_param;
        __u32                   serial;
+       int                     length;
 
        if (!sctp_vtag_verify(chunk, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
@@ -3222,6 +3420,15 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
        }
 
+       /* ADD-IP: Section 4.1.1
+        * This chunk MUST be sent in an authenticated way by using
+        * the mechanism defined in [I-D.ietf-tsvwg-sctp-auth]. If this chunk
+        * is received unauthenticated it MUST be silently discarded as
+        * described in [I-D.ietf-tsvwg-sctp-auth].
+        */
+       if (!sctp_addip_noauth && !chunk->auth)
+               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+
        /* Make sure that the ASCONF ADDIP chunk has a valid length.  */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_addip_chunk_t)))
                return sctp_sf_violation_chunklen(ep, asoc, type, arg,
@@ -3230,44 +3437,78 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
        hdr = (sctp_addiphdr_t *)chunk->skb->data;
        serial = ntohl(hdr->serial);
 
-       /* ADDIP 4.2 C1) Compare the value of the serial number to the value
+       addr_param = (union sctp_addr_param *)hdr->params;
+       length = ntohs(addr_param->p.length);
+       if (length < sizeof(sctp_paramhdr_t))
+               return sctp_sf_violation_paramlen(ep, asoc, type,
+                          (void *)addr_param, commands);
+
+       /* Verify the ASCONF chunk before processing it. */
+       if (!sctp_verify_asconf(asoc,
+                           (sctp_paramhdr_t *)((void *)addr_param + length),
+                           (void *)chunk->chunk_end,
+                           &err_param))
+               return sctp_sf_violation_paramlen(ep, asoc, type,
+                                                 (void *)&err_param, commands);
+
+       /* ADDIP 5.2 E1) Compare the value of the serial number to the value
         * the endpoint stored in a new association variable
-        * 'Peer-Serial-Number'. 
+        * 'Peer-Serial-Number'.
         */
        if (serial == asoc->peer.addip_serial + 1) {
-               /* ADDIP 4.2 C2) If the value found in the serial number is
-                * equal to the ('Peer-Serial-Number' + 1), the endpoint MUST
-                * do V1-V5.
+               /* If this is the first instance of ASCONF in the packet,
+                * we can clean our old ASCONF-ACKs.
+                */
+               if (!chunk->has_asconf)
+                       sctp_assoc_clean_asconf_ack_cache(asoc);
+
+               /* ADDIP 5.2 E4) When the Sequence Number matches the next one
+                * expected, process the ASCONF as described below and after
+                * processing the ASCONF Chunk, append an ASCONF-ACK Chunk to
+                * the response packet and cache a copy of it (in the event it
+                * later needs to be retransmitted).
+                *
+                * Essentially, do V1-V5.
                 */
                asconf_ack = sctp_process_asconf((struct sctp_association *)
                                                 asoc, chunk);
                if (!asconf_ack)
                        return SCTP_DISPOSITION_NOMEM;
-       } else if (serial == asoc->peer.addip_serial) {
-               /* ADDIP 4.2 C3) If the value found in the serial number is
-                * equal to the value stored in the 'Peer-Serial-Number'
-                * IMPLEMENTATION NOTE: As an optimization a receiver may wish
-                * to save the last ASCONF-ACK for some predetermined period of
-                * time and instead of re-processing the ASCONF (with the same
-                * serial number) it may just re-transmit the ASCONF-ACK.
+       } else if (serial < asoc->peer.addip_serial + 1) {
+               /* ADDIP 5.2 E2)
+                * If the value found in the Sequence Number is less than the
+                * ('Peer- Sequence-Number' + 1), simply skip to the next
+                * ASCONF, and include in the outbound response packet
+                * any previously cached ASCONF-ACK response that was
+                * sent and saved that matches the Sequence Number of the
+                * ASCONF.  Note: It is possible that no cached ASCONF-ACK
+                * Chunk exists.  This will occur when an older ASCONF
+                * arrives out of order.  In such a case, the receiver
+                * should skip the ASCONF Chunk and not include ASCONF-ACK
+                * Chunk for that chunk.
                 */
-               if (asoc->addip_last_asconf_ack)
-                       asconf_ack = asoc->addip_last_asconf_ack;
-               else
+               asconf_ack = sctp_assoc_lookup_asconf_ack(asoc, hdr->serial);
+               if (!asconf_ack)
                        return SCTP_DISPOSITION_DISCARD;
        } else {
-               /* ADDIP 4.2 C4) Otherwise, the ASCONF Chunk is discarded since 
+               /* ADDIP 5.2 E5) Otherwise, the ASCONF Chunk is discarded since
                 * it must be either a stale packet or from an attacker.
-                */     
+                */
                return SCTP_DISPOSITION_DISCARD;
        }
 
-       /* ADDIP 4.2 C5) In both cases C2 and C3 the ASCONF-ACK MUST be sent
-        * back to the source address contained in the IP header of the ASCONF
-        * being responded to.
+       /* ADDIP 5.2 E6)  The destination address of the SCTP packet
+        * containing the ASCONF-ACK Chunks MUST be the source address of
+        * the SCTP packet that held the ASCONF Chunks.
+        *
+        * To do this properly, we'll set the destination address of the chunk
+        * and at the transmit time, will try look up the transport to use.
+        * Since ASCONFs may be bundled, the correct transport may not be
+        * created untill we process the entire packet, thus this workaround.
         */
+       asconf_ack->dest = chunk->source;
        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack));
-       
+
        return SCTP_DISPOSITION_CONSUME;
 }
 
@@ -3278,12 +3519,13 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
  */
 sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
                                         const struct sctp_association *asoc,
-                                        const sctp_subtype_t type, void *arg,
+                                        const sctp_subtype_t type, void *arg,
                                         sctp_cmd_seq_t *commands)
 {
        struct sctp_chunk       *asconf_ack = arg;
        struct sctp_chunk       *last_asconf = asoc->addip_last_asconf;
        struct sctp_chunk       *abort;
+       struct sctp_paramhdr    *err_param = NULL;
        sctp_addiphdr_t         *addip_hdr;
        __u32                   sent_serial, rcvd_serial;
 
@@ -3293,6 +3535,15 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
        }
 
+       /* ADD-IP, Section 4.1.2:
+        * This chunk MUST be sent in an authenticated way by using
+        * the mechanism defined in [I-D.ietf-tsvwg-sctp-auth]. If this chunk
+        * is received unauthenticated it MUST be silently discarded as
+        * described in [I-D.ietf-tsvwg-sctp-auth].
+        */
+       if (!sctp_addip_noauth && !asconf_ack->auth)
+               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+
        /* Make sure that the ADDIP chunk has a valid length.  */
        if (!sctp_chunk_length_valid(asconf_ack, sizeof(sctp_addip_chunk_t)))
                return sctp_sf_violation_chunklen(ep, asoc, type, arg,
@@ -3301,6 +3552,14 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
        addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data;
        rcvd_serial = ntohl(addip_hdr->serial);
 
+       /* Verify the ASCONF-ACK chunk before processing it. */
+       if (!sctp_verify_asconf(asoc,
+           (sctp_paramhdr_t *)addip_hdr->params,
+           (void *)asconf_ack->chunk_end,
+           &err_param))
+               return sctp_sf_violation_paramlen(ep, asoc, type,
+                          (void *)&err_param, commands);
+
        if (last_asconf) {
                addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr;
                sent_serial = ntohl(addip_hdr->serial);
@@ -3319,7 +3578,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
                abort = sctp_make_abort(asoc, asconf_ack,
                                        sizeof(sctp_errhdr_t));
                if (abort) {
-                       sctp_init_cause(abort, SCTP_ERROR_ASCONF_ACK, NULL, 0);
+                       sctp_init_cause(abort, SCTP_ERROR_ASCONF_ACK, 0);
                        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
                                        SCTP_CHUNK(abort));
                }
@@ -3329,8 +3588,10 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
                sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                                SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
                sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
+               sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                               SCTP_ERROR(ECONNABORTED));
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-                               SCTP_U32(SCTP_ERROR_ASCONF_ACK));
+                               SCTP_PERR(SCTP_ERROR_ASCONF_ACK));
                SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
                SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_ABORT;
@@ -3347,7 +3608,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
                abort = sctp_make_abort(asoc, asconf_ack,
                                        sizeof(sctp_errhdr_t));
                if (abort) {
-                       sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, NULL, 0);
+                       sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, 0);
                        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
                                        SCTP_CHUNK(abort));
                }
@@ -3355,8 +3616,10 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
                 * processing the rest of the chunks in the packet.
                 */
                sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
+               sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                               SCTP_ERROR(ECONNABORTED));
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-                               SCTP_U32(SCTP_ERROR_ASCONF_ACK));
+                               SCTP_PERR(SCTP_ERROR_ASCONF_ACK));
                SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
                SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_ABORT;
@@ -3418,22 +3681,19 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
 
        sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn));
        if (len > sizeof(struct sctp_fwdtsn_hdr))
-               sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, 
+               sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN,
                                SCTP_CHUNK(chunk));
-       
+
        /* Count this as receiving DATA. */
        if (asoc->autoclose) {
                sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
                                SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
        }
-       
+
        /* FIXME: For now send a SACK, but DATA processing may
-        * send another. 
+        * send another.
         */
        sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE());
-       /* Start the SACK timer.  */
-       sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
-                       SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
 
        return SCTP_DISPOSITION_CONSUME;
 
@@ -3481,9 +3741,9 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
 
        sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn));
        if (len > sizeof(struct sctp_fwdtsn_hdr))
-               sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, 
+               sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN,
                                SCTP_CHUNK(chunk));
-       
+
        /* Go a head and force a SACK, since we are shutting down. */
 gen_shutdown:
        /* Implementor's Guide.
@@ -3497,7 +3757,170 @@ gen_shutdown:
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
 
-        return SCTP_DISPOSITION_CONSUME;
+       return SCTP_DISPOSITION_CONSUME;
+}
+
+/*
+ * SCTP-AUTH Section 6.3 Receving authenticated chukns
+ *
+ *    The receiver MUST use the HMAC algorithm indicated in the HMAC
+ *    Identifier field.  If this algorithm was not specified by the
+ *    receiver in the HMAC-ALGO parameter in the INIT or INIT-ACK chunk
+ *    during association setup, the AUTH chunk and all chunks after it MUST
+ *    be discarded and an ERROR chunk SHOULD be sent with the error cause
+ *    defined in Section 4.1.
+ *
+ *    If an endpoint with no shared key receives a Shared Key Identifier
+ *    other than 0, it MUST silently discard all authenticated chunks.  If
+ *    the endpoint has at least one endpoint pair shared key for the peer,
+ *    it MUST use the key specified by the Shared Key Identifier if a
+ *    key has been configured for that Shared Key Identifier.  If no
+ *    endpoint pair shared key has been configured for that Shared Key
+ *    Identifier, all authenticated chunks MUST be silently discarded.
+ *
+ * Verification Tag:  8.5 Verification Tag [Normal verification]
+ *
+ * The return value is the disposition of the chunk.
+ */
+static sctp_ierror_t sctp_sf_authenticate(const struct sctp_endpoint *ep,
+                                   const struct sctp_association *asoc,
+                                   const sctp_subtype_t type,
+                                   struct sctp_chunk *chunk)
+{
+       struct sctp_authhdr *auth_hdr;
+       struct sctp_hmac *hmac;
+       unsigned int sig_len;
+       __u16 key_id;
+       __u8 *save_digest;
+       __u8 *digest;
+
+       /* Pull in the auth header, so we can do some more verification */
+       auth_hdr = (struct sctp_authhdr *)chunk->skb->data;
+       chunk->subh.auth_hdr = auth_hdr;
+       skb_pull(chunk->skb, sizeof(struct sctp_authhdr));
+
+       /* Make sure that we suport the HMAC algorithm from the auth
+        * chunk.
+        */
+       if (!sctp_auth_asoc_verify_hmac_id(asoc, auth_hdr->hmac_id))
+               return SCTP_IERROR_AUTH_BAD_HMAC;
+
+       /* Make sure that the provided shared key identifier has been
+        * configured
+        */
+       key_id = ntohs(auth_hdr->shkey_id);
+       if (key_id != asoc->active_key_id && !sctp_auth_get_shkey(asoc, key_id))
+               return SCTP_IERROR_AUTH_BAD_KEYID;
+
+
+       /* Make sure that the length of the signature matches what
+        * we expect.
+        */
+       sig_len = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_auth_chunk_t);
+       hmac = sctp_auth_get_hmac(ntohs(auth_hdr->hmac_id));
+       if (sig_len != hmac->hmac_len)
+               return SCTP_IERROR_PROTO_VIOLATION;
+
+       /* Now that we've done validation checks, we can compute and
+        * verify the hmac.  The steps involved are:
+        *  1. Save the digest from the chunk.
+        *  2. Zero out the digest in the chunk.
+        *  3. Compute the new digest
+        *  4. Compare saved and new digests.
+        */
+       digest = auth_hdr->hmac;
+       skb_pull(chunk->skb, sig_len);
+
+       save_digest = kmemdup(digest, sig_len, GFP_ATOMIC);
+       if (!save_digest)
+               goto nomem;
+
+       memset(digest, 0, sig_len);
+
+       sctp_auth_calculate_hmac(asoc, chunk->skb,
+                               (struct sctp_auth_chunk *)chunk->chunk_hdr,
+                               GFP_ATOMIC);
+
+       /* Discard the packet if the digests do not match */
+       if (memcmp(save_digest, digest, sig_len)) {
+               kfree(save_digest);
+               return SCTP_IERROR_BAD_SIG;
+       }
+
+       kfree(save_digest);
+       chunk->auth = 1;
+
+       return SCTP_IERROR_NO_ERROR;
+nomem:
+       return SCTP_IERROR_NOMEM;
+}
+
+sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep,
+                                   const struct sctp_association *asoc,
+                                   const sctp_subtype_t type,
+                                   void *arg,
+                                   sctp_cmd_seq_t *commands)
+{
+       struct sctp_authhdr *auth_hdr;
+       struct sctp_chunk *chunk = arg;
+       struct sctp_chunk *err_chunk;
+       sctp_ierror_t error;
+
+       if (!sctp_vtag_verify(chunk, asoc)) {
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
+                               SCTP_NULL());
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+       }
+
+       /* Make sure that the AUTH chunk has valid length.  */
+       if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_auth_chunk)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
+       auth_hdr = (struct sctp_authhdr *)chunk->skb->data;
+       error = sctp_sf_authenticate(ep, asoc, type, chunk);
+       switch (error) {
+               case SCTP_IERROR_AUTH_BAD_HMAC:
+                       /* Generate the ERROR chunk and discard the rest
+                        * of the packet
+                        */
+                       err_chunk = sctp_make_op_error(asoc, chunk,
+                                                       SCTP_ERROR_UNSUP_HMAC,
+                                                       &auth_hdr->hmac_id,
+                                                       sizeof(__u16));
+                       if (err_chunk) {
+                               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
+                                               SCTP_CHUNK(err_chunk));
+                       }
+                       /* Fall Through */
+               case SCTP_IERROR_AUTH_BAD_KEYID:
+               case SCTP_IERROR_BAD_SIG:
+                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       break;
+               case SCTP_IERROR_PROTO_VIOLATION:
+                       return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                         commands);
+                       break;
+               case SCTP_IERROR_NOMEM:
+                       return SCTP_DISPOSITION_NOMEM;
+               default:
+                       break;
+       }
+
+       if (asoc->active_key_id != ntohs(auth_hdr->shkey_id)) {
+               struct sctp_ulpevent *ev;
+
+               ev = sctp_ulpevent_make_authkey(asoc, ntohs(auth_hdr->shkey_id),
+                                   SCTP_AUTH_NEWKEY, GFP_ATOMIC);
+
+               if (!ev)
+                       return -ENOMEM;
+
+               sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+                               SCTP_ULPEVENT(ev));
+       }
+
+       return SCTP_DISPOSITION_CONSUME;
 }
 
 /*
@@ -3610,6 +4033,16 @@ sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep,
                                         void *arg,
                                         sctp_cmd_seq_t *commands)
 {
+       struct sctp_chunk *chunk = arg;
+
+       /* Make sure that the chunk has a valid length.
+        * Since we don't know the chunk type, we use a general
+        * chunkhdr structure to make a comparison.
+        */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk);
        return SCTP_DISPOSITION_DISCARD;
 }
@@ -3638,6 +4071,7 @@ sctp_disposition_t sctp_sf_pdiscard(const struct sctp_endpoint *ep,
                                    void *arg,
                                    sctp_cmd_seq_t *commands)
 {
+       SCTP_INC_STATS(SCTP_MIB_IN_PKT_DISCARDS);
        sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
 
        return SCTP_DISPOSITION_CONSUME;
@@ -3664,9 +4098,99 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
                                     void *arg,
                                     sctp_cmd_seq_t *commands)
 {
+       struct sctp_chunk *chunk = arg;
+
+       /* Make sure that the chunk has a valid length. */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        return SCTP_DISPOSITION_VIOLATION;
 }
 
+/*
+ * Common function to handle a protocol violation.
+ */
+static sctp_disposition_t sctp_sf_abort_violation(
+                                    const struct sctp_endpoint *ep,
+                                    const struct sctp_association *asoc,
+                                    void *arg,
+                                    sctp_cmd_seq_t *commands,
+                                    const __u8 *payload,
+                                    const size_t paylen)
+{
+       struct sctp_packet *packet = NULL;
+       struct sctp_chunk *chunk =  arg;
+       struct sctp_chunk *abort = NULL;
+
+       /* SCTP-AUTH, Section 6.3:
+        *    It should be noted that if the receiver wants to tear
+        *    down an association in an authenticated way only, the
+        *    handling of malformed packets should not result in
+        *    tearing down the association.
+        *
+        * This means that if we only want to abort associations
+        * in an authenticated way (i.e AUTH+ABORT), then we
+        * can't destory this association just becuase the packet
+        * was malformed.
+        */
+       if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
+               goto discard;
+
+       /* Make the abort chunk. */
+       abort = sctp_make_abort_violation(asoc, chunk, payload, paylen);
+       if (!abort)
+               goto nomem;
+
+       if (asoc) {
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+
+               if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) {
+                       sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+                                       SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+                       sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                                       SCTP_ERROR(ECONNREFUSED));
+                       sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
+                                       SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION));
+               } else {
+                       sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                                       SCTP_ERROR(ECONNABORTED));
+                       sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+                                       SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION));
+                       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+               }
+       } else {
+               packet = sctp_ootb_pkt_new(asoc, chunk);
+
+               if (!packet)
+                       goto nomem_pkt;
+
+               if (sctp_test_T_bit(abort))
+                       packet->vtag = ntohl(chunk->sctp_hdr->vtag);
+
+               abort->skb->sk = ep->base.sk;
+
+               sctp_packet_append_chunk(packet, abort);
+
+               sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
+                       SCTP_PACKET(packet));
+
+               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+       }
+
+discard:
+       sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands);
+
+       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+
+       return SCTP_DISPOSITION_ABORT;
+
+nomem_pkt:
+       sctp_chunk_free(abort);
+nomem:
+       return SCTP_DISPOSITION_NOMEM;
+}
 
 /*
  * Handle a protocol violation when the chunk length is invalid.
@@ -3675,7 +4199,7 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
  * if it's length is set to be smaller then the size of sctp_sack_chunk_t.
  *
  * We inform the other end by sending an ABORT with a Protocol Violation
- * error code. 
+ * error code.
  *
  * Section: Not specified
  * Verification Tag:  Nothing to do
@@ -3687,46 +4211,76 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
  *
  * Generate an  ABORT chunk and terminate the association.
  */
-sctp_disposition_t sctp_sf_violation_chunklen(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_violation_chunklen(
+                                    const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
                                     void *arg,
                                     sctp_cmd_seq_t *commands)
 {
-       struct sctp_chunk *chunk =  arg;
-       struct sctp_chunk *abort = NULL;
-       char               err_str[]="The following chunk had invalid length:";
+       char err_str[]="The following chunk had invalid length:";
 
-       /* Make the abort chunk. */
-       abort = sctp_make_abort_violation(asoc, chunk, err_str,
-                                         sizeof(err_str));
-       if (!abort)
-               goto nomem;
-
-       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
-       SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+       return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
+                                       sizeof(err_str));
+}
 
-       if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) {
-               sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
-                               SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
-               sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
-                               SCTP_U32(SCTP_ERROR_PROTO_VIOLATION));
-       } else {
-               sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-                               SCTP_U32(SCTP_ERROR_PROTO_VIOLATION));
-               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
-       }
+/*
+ * Handle a protocol violation when the parameter length is invalid.
+ * "Invalid" length is identified as smaller then the minimal length a
+ * given parameter can be.
+ */
+static sctp_disposition_t sctp_sf_violation_paramlen(
+                                    const struct sctp_endpoint *ep,
+                                    const struct sctp_association *asoc,
+                                    const sctp_subtype_t type,
+                                    void *arg,
+                                    sctp_cmd_seq_t *commands) {
+       char err_str[] = "The following parameter had invalid length:";
 
-       sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
+       return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
+                                       sizeof(err_str));
+}
 
-       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-       
-       return SCTP_DISPOSITION_ABORT;
+/* Handle a protocol violation when the peer trying to advance the
+ * cumulative tsn ack to a point beyond the max tsn currently sent.
+ *
+ * We inform the other end by sending an ABORT with a Protocol Violation
+ * error code.
+ */
+static sctp_disposition_t sctp_sf_violation_ctsn(
+                                    const struct sctp_endpoint *ep,
+                                    const struct sctp_association *asoc,
+                                    const sctp_subtype_t type,
+                                    void *arg,
+                                    sctp_cmd_seq_t *commands)
+{
+       char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:";
 
-nomem:
-       return SCTP_DISPOSITION_NOMEM;
+       return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
+                                       sizeof(err_str));
 }
 
+/* Handle protocol violation of an invalid chunk bundling.  For example,
+ * when we have an association and we recieve bundled INIT-ACK, or
+ * SHUDOWN-COMPLETE, our peer is clearly violationg the "MUST NOT bundle"
+ * statement from the specs.  Additinally, there might be an attacker
+ * on the path and we may not want to continue this communication.
+ */
+static sctp_disposition_t sctp_sf_violation_chunk(
+                                    const struct sctp_endpoint *ep,
+                                    const struct sctp_association *asoc,
+                                    const sctp_subtype_t type,
+                                    void *arg,
+                                    sctp_cmd_seq_t *commands)
+{
+       char err_str[]="The following chunk violates protocol:";
+
+       if (!asoc)
+               return sctp_sf_violation(ep, asoc, type, arg, commands);
+
+       return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
+                                       sizeof(err_str));
+}
 /***************************************************************************
  * These are the state functions for handling primitive (Section 10) events.
  ***************************************************************************/
@@ -4012,26 +4566,22 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(
         * from its upper layer, but retransmits data to the far end
         * if necessary to fill gaps.
         */
-       struct msghdr *msg = arg;
-       struct sctp_chunk *abort;
+       struct sctp_chunk *abort = arg;
        sctp_disposition_t retval;
 
        retval = SCTP_DISPOSITION_CONSUME;
 
-       /* Generate ABORT chunk to send the peer.  */
-       abort = sctp_make_abort_user(asoc, NULL, msg);
-       if (!abort)
-               retval = SCTP_DISPOSITION_NOMEM;
-       else
-               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
 
        /* Even if we can't send the ABORT due to low memory delete the
         * TCB.  This is a departure from our typical NOMEM handling.
         */
 
+       sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                       SCTP_ERROR(ECONNABORTED));
        /* Delete the established association. */
        sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-                       SCTP_U32(SCTP_ERROR_USER_ABORT));
+                       SCTP_PERR(SCTP_ERROR_USER_ABORT));
 
        SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
        SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
@@ -4145,8 +4695,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
        void *arg,
        sctp_cmd_seq_t *commands)
 {
-       struct msghdr *msg = arg;
-       struct sctp_chunk *abort;
+       struct sctp_chunk *abort = arg;
        sctp_disposition_t retval;
 
        /* Stop T1-init timer */
@@ -4154,12 +4703,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
        retval = SCTP_DISPOSITION_CONSUME;
 
-       /* Generate ABORT chunk to send the peer */
-       abort = sctp_make_abort_user(asoc, NULL, msg);
-       if (!abort)
-               retval = SCTP_DISPOSITION_NOMEM;
-       else
-               sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
 
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
@@ -4170,9 +4714,11 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
         * TCB.  This is a departure from our typical NOMEM handling.
         */
 
+       sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                       SCTP_ERROR(ECONNREFUSED));
        /* Delete the established association. */
        sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
-                       SCTP_U32(SCTP_ERROR_USER_ABORT));
+                       SCTP_PERR(SCTP_ERROR_USER_ABORT));
 
        return retval;
 }
@@ -4314,8 +4860,24 @@ sctp_disposition_t sctp_sf_do_prm_requestheartbeat(
                                        void *arg,
                                        sctp_cmd_seq_t *commands)
 {
-       return sctp_sf_heartbeat(ep, asoc, type, (struct sctp_transport *)arg,
-                                commands);
+       if (SCTP_DISPOSITION_NOMEM == sctp_sf_heartbeat(ep, asoc, type,
+                                     (struct sctp_transport *)arg, commands))
+               return SCTP_DISPOSITION_NOMEM;
+
+       /*
+        * RFC 2960 (bis), section 8.3
+        *
+        *    D) Request an on-demand HEARTBEAT on a specific destination
+        *    transport address of a given association.
+        *
+        *    The endpoint should increment the respective error  counter of
+        *    the destination transport address each time a HEARTBEAT is sent
+        *    to that address and not acknowledged within one RTO.
+        *
+        */
+       sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET,
+                       SCTP_TRANSPORT(arg));
+       return SCTP_DISPOSITION_CONSUME;
 }
 
 /*
@@ -4409,7 +4971,7 @@ sctp_disposition_t sctp_sf_do_9_2_start_shutdown(
        /* sctp-implguide 2.10 Issues with Heartbeating and failover
         *
         * HEARTBEAT ... is discontinued after sending either SHUTDOWN
-         * or SHUTDOWN-ACK.
+        * or SHUTDOWN-ACK.
         */
        sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_STOP, SCTP_NULL());
 
@@ -4487,7 +5049,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(
        /* sctp-implguide 2.10 Issues with Heartbeating and failover
         *
         * HEARTBEAT ... is discontinued after sending either SHUTDOWN
-         * or SHUTDOWN-ACK.
+        * or SHUTDOWN-ACK.
         */
        sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_STOP, SCTP_NULL());
 
@@ -4537,10 +5099,14 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
 {
        struct sctp_transport *transport = arg;
 
+       SCTP_INC_STATS(SCTP_MIB_T3_RTX_EXPIREDS);
+
        if (asoc->overall_error_count >= asoc->max_retrans) {
+               sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                               SCTP_ERROR(ETIMEDOUT));
                /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-                               SCTP_U32(SCTP_ERROR_NO_ERROR));
+                               SCTP_PERR(SCTP_ERROR_NO_ERROR));
                SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
                SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_DELETE_TCB;
@@ -4573,12 +5139,12 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
         * sent as soon as cwnd allows (normally when a SACK arrives).
         */
 
-       /* NB: Rules E4 and F1 are implicit in R1.  */
-       sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(transport));
-
        /* Do some failure management (Section 8.2). */
        sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport));
 
+       /* NB: Rules E4 and F1 are implicit in R1.  */
+       sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(transport));
+
        return SCTP_DISPOSITION_CONSUME;
 }
 
@@ -4603,6 +5169,7 @@ sctp_disposition_t sctp_sf_do_6_2_sack(const struct sctp_endpoint *ep,
                                       void *arg,
                                       sctp_cmd_seq_t *commands)
 {
+       SCTP_INC_STATS(SCTP_MIB_DELAY_SACK_EXPIREDS);
        sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE());
        return SCTP_DISPOSITION_CONSUME;
 }
@@ -4637,8 +5204,9 @@ sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep,
        int attempts = asoc->init_err_counter + 1;
 
        SCTP_DEBUG_PRINTK("Timer T1 expired (INIT).\n");
+       SCTP_INC_STATS(SCTP_MIB_T1_INIT_EXPIREDS);
 
-       if (attempts < asoc->max_init_attempts) {
+       if (attempts <= asoc->max_init_attempts) {
                bp = (struct sctp_bind_addr *) &asoc->base.bind_addr;
                repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0);
                if (!repl)
@@ -4657,8 +5225,10 @@ sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep,
                SCTP_DEBUG_PRINTK("Giving up on INIT, attempts: %d"
                                  " max_init_attempts: %d\n",
                                  attempts, asoc->max_init_attempts);
+               sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                               SCTP_ERROR(ETIMEDOUT));
                sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
-                               SCTP_U32(SCTP_ERROR_NO_ERROR));
+                               SCTP_PERR(SCTP_ERROR_NO_ERROR));
                return SCTP_DISPOSITION_DELETE_TCB;
        }
 
@@ -4694,8 +5264,9 @@ sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep
        int attempts = asoc->init_err_counter + 1;
 
        SCTP_DEBUG_PRINTK("Timer T1 expired (COOKIE-ECHO).\n");
+       SCTP_INC_STATS(SCTP_MIB_T1_COOKIE_EXPIREDS);
 
-       if (attempts < asoc->max_init_attempts) {
+       if (attempts <= asoc->max_init_attempts) {
                repl = sctp_make_cookie_echo(asoc, NULL);
                if (!repl)
                        return SCTP_DISPOSITION_NOMEM;
@@ -4706,8 +5277,10 @@ sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep
 
                sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
        } else {
+               sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                               SCTP_ERROR(ETIMEDOUT));
                sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
-                               SCTP_U32(SCTP_ERROR_NO_ERROR));
+                               SCTP_PERR(SCTP_ERROR_NO_ERROR));
                return SCTP_DISPOSITION_DELETE_TCB;
        }
 
@@ -4736,10 +5309,14 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
        struct sctp_chunk *reply = NULL;
 
        SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
+       SCTP_INC_STATS(SCTP_MIB_T2_SHUTDOWN_EXPIREDS);
+
        if (asoc->overall_error_count >= asoc->max_retrans) {
+               sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                               SCTP_ERROR(ETIMEDOUT));
                /* Note:  CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-                               SCTP_U32(SCTP_ERROR_NO_ERROR));
+                               SCTP_PERR(SCTP_ERROR_NO_ERROR));
                SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
                SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_DELETE_TCB;
@@ -4757,7 +5334,7 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
        default:
                BUG();
                break;
-       };
+       }
 
        if (!reply)
                goto nomem;
@@ -4795,6 +5372,8 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
        struct sctp_chunk *chunk = asoc->addip_last_asconf;
        struct sctp_transport *transport = chunk->transport;
 
+       SCTP_INC_STATS(SCTP_MIB_T4_RTO_EXPIREDS);
+
        /* ADDIP 4.1 B1) Increment the error counters and perform path failure
         * detection on the appropriate destination address as defined in
         * RFC2960 [5] section 8.1 and 8.2.
@@ -4812,8 +5391,10 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
        if (asoc->overall_error_count >= asoc->max_retrans) {
                sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                                SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
+               sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                               SCTP_ERROR(ETIMEDOUT));
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-                               SCTP_U32(SCTP_ERROR_NO_ERROR));
+                               SCTP_PERR(SCTP_ERROR_NO_ERROR));
                SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
                SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_ABORT;
@@ -4827,7 +5408,7 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
        /* ADDIP 4.1 B4) Re-transmit the ASCONF Chunk last sent and if possible
         * choose an alternate destination address (please refer to RFC2960
         * [5] section 6.4.1). An endpoint MUST NOT add new parameters to this
-        * chunk, it MUST be the same (including its serial number) as the last 
+        * chunk, it MUST be the same (including its serial number) as the last
         * ASCONF sent.
         */
        sctp_chunk_hold(asoc->addip_last_asconf);
@@ -4859,14 +5440,17 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const struct sctp_endpoint *ep,
        struct sctp_chunk *reply = NULL;
 
        SCTP_DEBUG_PRINTK("Timer T5 expired.\n");
+       SCTP_INC_STATS(SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS);
 
        reply = sctp_make_abort(asoc, NULL, 0);
        if (!reply)
                goto nomem;
 
        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
+       sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                       SCTP_ERROR(ETIMEDOUT));
        sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-                       SCTP_U32(SCTP_ERROR_NO_ERROR));
+                       SCTP_PERR(SCTP_ERROR_NO_ERROR));
 
        return SCTP_DISPOSITION_DELETE_TCB;
 nomem:
@@ -4887,6 +5471,8 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(
 {
        int disposition;
 
+       SCTP_INC_STATS(SCTP_MIB_AUTOCLOSE_EXPIREDS);
+
        /* From 9.2 Shutdown of an Association
         * Upon receipt of the SHUTDOWN primitive from its upper
         * layer, the endpoint enters SHUTDOWN-PENDING state and
@@ -4901,7 +5487,7 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(
        /* sctpimpguide-05 Section 2.12.2
         * The sender of the SHUTDOWN MAY also start an overall guard timer
         * 'T5-shutdown-guard' to bound the overall time for shutdown sequence.
-        */
+        */
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
        disposition = SCTP_DISPOSITION_CONSUME;
@@ -5061,7 +5647,22 @@ static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc
         * association exists, otherwise, use the peer's vtag.
         */
        if (asoc) {
-               vtag = asoc->peer.i.init_tag;
+               /* Special case the INIT-ACK as there is no peer's vtag
+                * yet.
+                */
+               switch(chunk->chunk_hdr->type) {
+               case SCTP_CID_INIT_ACK:
+               {
+                       sctp_initack_chunk_t *initack;
+
+                       initack = (sctp_initack_chunk_t *)chunk->chunk_hdr;
+                       vtag = ntohl(initack->init_hdr.init_tag);
+                       break;
+               }
+               default:
+                       vtag = asoc->peer.i.init_tag;
+                       break;
+               }
        } else {
                /* Special case the INIT and stale COOKIE_ECHO as there is no
                 * vtag yet.
@@ -5075,7 +5676,7 @@ static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc
                        vtag = ntohl(init->init_hdr.init_tag);
                        break;
                }
-               default:        
+               default:
                        vtag = ntohl(chunk->sctp_hdr->vtag);
                        break;
                }
@@ -5124,7 +5725,7 @@ static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
                        /* Override the OOTB vtag from the cookie. */
                        cookie = chunk->subh.cookie_hdr;
                        packet->vtag = cookie->c.peer_vtag;
-                       
+
                        /* Set the skb to the belonging sock for accounting. */
                        err_chunk->skb->sk = ep->base.sk;
                        sctp_packet_append_chunk(packet, err_chunk);
@@ -5148,6 +5749,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
        sctp_verb_t deliver;
        int tmp;
        __u32 tsn;
+       struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
+       struct sock *sk = asoc->base.sk;
 
        data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data;
        skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
@@ -5172,7 +5775,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
                chunk->ecn_ce_done = 1;
 
                af = sctp_get_af_specific(
-                       ipver2af(chunk->skb->nh.iph->version));
+                       ipver2af(ip_hdr(chunk->skb)->version));
 
                if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
                        /* Do real work as sideffect. */
@@ -5212,13 +5815,13 @@ static int sctp_eat_data(const struct sctp_association *asoc,
                sctp_add_cmd_sf(commands, SCTP_CMD_PART_DELIVER, SCTP_NULL());
        }
 
-        /* Spill over rwnd a little bit.  Note: While allowed, this spill over
+       /* Spill over rwnd a little bit.  Note: While allowed, this spill over
         * seems a bit troublesome in that frag_point varies based on
         * PMTU.  In cases, such as loopback, this might be a rather
         * large spill over.
         */
-       if (!asoc->rwnd || asoc->rwnd_over ||
-           (datalen > asoc->rwnd + asoc->frag_point)) {
+       if ((!chunk->data_accepted) && (!asoc->rwnd || asoc->rwnd_over ||
+           (datalen > asoc->rwnd + asoc->frag_point))) {
 
                /* If this is the next TSN, consider reneging to make
                 * room.   Note: Playing nice with a confused sender.  A
@@ -5226,8 +5829,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
                 * space and in the future we may want to detect and
                 * do more drastic reneging.
                 */
-               if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) &&
-                   (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) {
+               if (sctp_tsnmap_has_gap(map) &&
+                   (sctp_tsnmap_get_ctsn(map) + 1) == tsn) {
                        SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn);
                        deliver = SCTP_CMD_RENEGE;
                } else {
@@ -5239,6 +5842,21 @@ static int sctp_eat_data(const struct sctp_association *asoc,
        }
 
        /*
+        * Also try to renege to limit our memory usage in the event that
+        * we are under memory pressure
+        * If we can't renege, don't worry about it, the sk_stream_rmem_schedule
+        * in sctp_ulpevent_make_rcvmsg will drop the frame if we grow our
+        * memory usage too much
+        */
+       if (*sk->sk_prot_creator->memory_pressure) {
+               if (sctp_tsnmap_has_gap(map) &&
+                  (sctp_tsnmap_get_ctsn(map) + 1) == tsn) {
+                       SCTP_DEBUG_PRINTK("Under Pressure! Reneging for tsn:%u\n", tsn);
+                       deliver = SCTP_CMD_RENEGE;
+                }
+       }
+
+       /*
         * Section 3.3.10.9 No User Data (9)
         *
         * Cause of error
@@ -5256,8 +5874,10 @@ static int sctp_eat_data(const struct sctp_association *asoc,
                 * processing the rest of the chunks in the packet.
                 */
                sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
+               sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                               SCTP_ERROR(ECONNABORTED));
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-                               SCTP_U32(SCTP_ERROR_NO_DATA));
+                               SCTP_PERR(SCTP_ERROR_NO_DATA));
                SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
                SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_IERROR_NO_DATA;
@@ -5269,6 +5889,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
        if (SCTP_CMD_CHUNK_ULP == deliver)
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
 
+       chunk->data_accepted = 1;
+
        /* Note: Some chunks may get overcounted (if we drop) or overcounted
         * if we renege and the chunk arrives again.
         */