vserver 1.9.5.x5
[linux-2.6.git] / net / sctp / sm_statefuns.c
index 30849b0..9b1b959 100644 (file)
 #include <net/sctp/sm.h>
 #include <net/sctp/structs.h>
 
+static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
+                                 const struct sctp_association *asoc,
+                                 struct sctp_chunk *chunk,
+                                 const void *payload,
+                                 size_t paylen);
+static int sctp_eat_data(const struct sctp_association *asoc,
+                        struct sctp_chunk *chunk,
+                        sctp_cmd_seq_t *commands);
+static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
+                                            const struct sctp_chunk *chunk);
+static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
+                                      const struct sctp_association *asoc,
+                                      const struct sctp_chunk *chunk,
+                                      sctp_cmd_seq_t *commands,
+                                      struct sctp_chunk *err_chunk);
+static sctp_disposition_t sctp_sf_do_5_2_6_stale(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_shut_8_4_5(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);
+
+
+/* Small helper function that checks if the chunk length
+ * is of the appropriate length.  The 'required_length' argument
+ * is set to be the size of a specific chunk we are testing.
+ * Return Values:  1 = Valid length
+ *                0 = Invalid length
+ *
+ */
+static inline int
+sctp_chunk_length_valid(struct sctp_chunk *chunk,
+                          __u16 required_length)
+{
+       __u16 chunk_length = ntohs(chunk->chunk_hdr->length);
+
+       if (unlikely(chunk_length < required_length))
+               return 0;
+
+       return 1;
+}
+
 /**********************************************************
  * These are the state functions for handling chunk events.
  **********************************************************/
@@ -148,8 +195,8 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
 
-       SCTP_INC_STATS(SctpShutdowns);
-       SCTP_DEC_STATS(SctpCurrEstab);
+       SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS);
+       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
 
        sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
 
@@ -199,9 +246,14 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
        /* 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
+        * with an INIT chunk that is bundled with other chunks.
         */
        if (!chunk->singleton)
-               return SCTP_DISPOSITION_VIOLATION;
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
        /* If the packet is an OOTB packet which is temporarily on the
         * control endpoint, respond with an ABORT.
@@ -225,6 +277,14 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
        if (chunk->sctp_hdr->vtag != 0)
                return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
+       /* Make sure that the INIT chunk has a valid length.
+        * Normally, this would cause an ABORT with a Protocol Violation
+        * error, but since we don't have an association, we'll
+        * just discard the packet.
+        */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t)))
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
        /* Verify the INIT chunk before processing it. */
        err_chunk = NULL;
        if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
@@ -245,7 +305,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
                        if (packet) {
                                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                                SCTP_PACKET(packet));
-                               SCTP_INC_STATS(SctpOutCtrlChunks);
+                               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
                                return SCTP_DISPOSITION_CONSUME;
                        } else {
                                return SCTP_DISPOSITION_NOMEM;
@@ -376,6 +436,13 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
        struct sctp_packet *packet;
        sctp_disposition_t ret;
 
+       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.
@@ -383,9 +450,6 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
        if (!chunk->singleton)
                return SCTP_DISPOSITION_VIOLATION;
 
-       if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-
        /* Grab the INIT header.  */
        chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
 
@@ -404,7 +468,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
                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(SctpAborteds);
+               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
                sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
                return SCTP_DISPOSITION_DELETE_TCB;
        }
@@ -415,7 +479,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
                              (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
                              &err_chunk)) {
 
-               SCTP_INC_STATS(SctpAborteds);
+               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.
@@ -432,7 +496,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
                        if (packet) {
                                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                                SCTP_PACKET(packet));
-                               SCTP_INC_STATS(SctpOutCtrlChunks);
+                               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,
@@ -472,8 +536,6 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
         */
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
-       sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_RESET,
-                       SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR));
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
@@ -544,6 +606,14 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
        if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
                return sctp_sf_ootb(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
+        * chunk header.  More detailed verification is done
+        * in sctp_unpack_cookie().
+        */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
        /* "Decode" the chunk.  We have no optional parameters so we
         * are in good shape.
         */
@@ -587,8 +657,8 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
        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(SctpCurrEstab);
-       SCTP_INC_STATS(SctpPassiveEstabs);
+       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)
@@ -631,6 +701,21 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(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
+        * delivers this notification to inform the application that of the
+        * peers requested adaption layer.
+        */
+       if (new_asoc->peer.adaption_ind) {
+               ev = sctp_ulpevent_make_adaption_indication(new_asoc,
+                                                           GFP_ATOMIC);
+               if (!ev)
+                       goto nomem_ev;
+
+               sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+                               SCTP_ULPEVENT(ev));
+       }
+
        return SCTP_DISPOSITION_CONSUME;
 
 nomem_ev:
@@ -674,6 +759,22 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* Verify that the chunk length for the COOKIE-ACK is OK.
+        * If we don't do this, any bundled chunks may be junked.
+        */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
+       /* Reset init error count upon receipt of COOKIE-ACK,
+        * to avoid problems with the managemement of this
+        * counter in stale cookie situations when a transition back
+        * from the COOKIE-ECHOED state to the COOKIE-WAIT
+        * state is performed.
+        */
+       sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_RESET,
+                       SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR));
+
        /* RFC 2960 5.1 Normal Establishment of an Association
         *
         * E) Upon reception of the COOKIE ACK, endpoint "A" will move
@@ -684,8 +785,8 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_ESTABLISHED));
-       SCTP_INC_STATS(SctpCurrEstab);
-       SCTP_INC_STATS(SctpActiveEstabs);
+       SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
+       SCTP_INC_STATS(SCTP_MIB_ACTIVEESTABS);
        sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
        if (asoc->autoclose)
                sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
@@ -706,17 +807,31 @@ 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
+        * delivers this notification to inform the application that of the
+        * peers requested adaption layer.
+        */
+       if (asoc->peer.adaption_ind) {
+               ev = sctp_ulpevent_make_adaption_indication(asoc, GFP_ATOMIC);
+               if (!ev)
+                       goto nomem;
+
+               sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+                               SCTP_ULPEVENT(ev));
+       }
+
        return SCTP_DISPOSITION_CONSUME;
 nomem:
        return SCTP_DISPOSITION_NOMEM;
 }
 
 /* Generate and sendout a heartbeat packet.  */
-sctp_disposition_t sctp_sf_heartbeat(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_heartbeat(const struct sctp_endpoint *ep,
+                                           const struct sctp_association *asoc,
+                                           const sctp_subtype_t type,
+                                           void *arg,
+                                           sctp_cmd_seq_t *commands)
 {
        struct sctp_transport *transport = (struct sctp_transport *) arg;
        struct sctp_chunk *reply;
@@ -757,8 +872,8 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
                /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_U32(SCTP_ERROR_NO_ERROR));
-               SCTP_INC_STATS(SctpAborteds);
-               SCTP_DEC_STATS(SctpCurrEstab);
+               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_DELETE_TCB;
        }
 
@@ -823,6 +938,11 @@ sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* Make sure that the HEARTBEAT chunk has a valid length. */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        /* 8.3 The receiver of the HEARTBEAT should immediately
         * respond with a HEARTBEAT ACK that contains the Heartbeat
         * Information field copied from the received HEARTBEAT chunk.
@@ -886,6 +1006,11 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* Make sure that the HEARTBEAT-ACK chunk has a valid length.  */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;
        from_addr = hbinfo->daddr;
        link = sctp_assoc_lookup_paddr(asoc, &from_addr);
@@ -960,7 +1085,7 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
                goto out;
        sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(pkt));
 
-       SCTP_INC_STATS(SctpOutCtrlChunks);
+       SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
 
        /* Discard the rest of the inbound packet. */
        sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
@@ -995,7 +1120,7 @@ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc,
        /* Search through all current addresses and make sure
         * we aren't adding any new ones.
         */
-       new_addr = 0;
+       new_addr = NULL;
        found = 0;
 
        list_for_each(pos, &new_asoc->peer.transport_addr_list) {
@@ -1129,9 +1254,14 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
        /* 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
+        * with an INIT chunk that is bundled with other chunks.
         */
        if (!chunk->singleton)
-               return SCTP_DISPOSITION_VIOLATION;
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
        /* 3.1 A packet containing an INIT chunk MUST have a zero Verification
         * Tag. 
@@ -1139,6 +1269,13 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
        if (chunk->sctp_hdr->vtag != 0)
                return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
+       /* Make sure that the INIT chunk has a valid length.
+        * In this case, we generate a protocol violation since we have
+        * an association established.
+        */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_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;
 
@@ -1163,7 +1300,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
                        if (packet) {
                                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                                SCTP_PACKET(packet));
-                               SCTP_INC_STATS(SctpOutCtrlChunks);
+                               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
                                retval = SCTP_DISPOSITION_CONSUME;
                        } else {
                                retval = SCTP_DISPOSITION_NOMEM;
@@ -1501,7 +1638,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_ESTABLISHED));
-       SCTP_INC_STATS(SctpCurrEstab);
+       SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
        sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
 
        repl = sctp_make_cookie_ack(new_asoc, chunk);
@@ -1525,6 +1662,21 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
                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
+        * delivers this notification to inform the application that of the
+        * peers requested adaption layer.
+        */
+       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));
+       }
+
        return SCTP_DISPOSITION_CONSUME;
 
 nomem_ev:
@@ -1585,7 +1737,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
                                SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
                sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                                SCTP_STATE(SCTP_STATE_ESTABLISHED));
-               SCTP_INC_STATS(SctpCurrEstab);
+               SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
                sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START,
                                SCTP_NULL());
 
@@ -1605,6 +1757,21 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
                        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,
+                * SCTP delivers this notification to inform the application
+                * that of the peers requested adaption layer.
+                */
+               if (new_asoc->peer.adaption_ind) {
+                       ev = sctp_ulpevent_make_adaption_indication(new_asoc,
+                                                                GFP_ATOMIC);
+                       if (!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());
 
@@ -1652,6 +1819,15 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
        char action;
        struct sctp_chunk *err_chk_p;
 
+       /* Make sure that the chunk has a valid length from the protocol
+        * perspective.  In this case check to make sure we have at least
+        * enough for the chunk header.  Cookie length verification is
+        * done later.
+        */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        /* "Decode" the chunk.  We have no optional parameters so we
         * are in good shape.
         */
@@ -1749,6 +1925,19 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(
        if (!sctp_vtag_verify_either(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* Make sure that the ABORT chunk has a valid length.
+        * Since this is an ABORT chunk, we have to discard it
+        * because of the following text:
+        * RFC 2960, Section 3.3.7
+        *    If an endpoint receives an ABORT with a format error or for an
+        *    association that doesn't exist, it MUST silently discard it.
+        * Becasue the length is "invalid", we can't really discard just
+        * as we do not know its true length.  So, to be safe, discard the
+        * packet.
+        */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+               return sctp_sf_pdiscard(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));
@@ -1772,6 +1961,19 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify_either(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* Make sure that the ABORT chunk has a valid length.
+        * Since this is an ABORT chunk, we have to discard it
+        * because of the following text:
+        * RFC 2960, Section 3.3.7
+        *    If an endpoint receives an ABORT with a format error or for an
+        *    association that doesn't exist, it MUST silently discard it.
+        * Becasue the length is "invalid", we can't really discard just
+        * as we do not know its true length.  So, to be safe, discard the
+        * packet.
+        */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+               return sctp_sf_pdiscard(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));
@@ -1824,6 +2026,16 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
        struct sctp_chunk *chunk = arg;
        sctp_errhdr_t *err;
 
+       if (!sctp_vtag_verify(chunk, asoc))
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+       /* Make sure that the ERROR chunk has a valid length.
+        * The parameter walking depends on this as well.
+        */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        /* Process the error here */
        /* FUTURE FIXME:  When PR-SCTP related and other optional
         * parms are emitted, this will have to change to handle multiple
@@ -1834,6 +2046,12 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
                        return sctp_sf_do_5_2_6_stale(ep, asoc, type, 
                                                        arg, commands);
        }
+
+       /* It is possible to have malformed error causes, and that
+        * will cause us to end the walk early.  However, since
+        * we are discarding the packet, there should be no adverse
+        * affects.
+        */
        return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 }
 
@@ -1862,18 +2080,16 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_2_6_stale(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_do_5_2_6_stale(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;
        time_t stale;
        sctp_cookie_preserve_param_t bht;
        sctp_errhdr_t *err;
-       struct list_head *pos;
-       struct sctp_transport *t;
        struct sctp_chunk *reply;
        struct sctp_bind_addr *bp;
        int attempts;
@@ -1920,20 +2136,27 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
        /* Clear peer's init_tag cached in assoc as we are sending a new INIT */
        sctp_add_cmd_sf(commands, SCTP_CMD_CLEAR_INIT_TAG, SCTP_NULL());
 
+       /* Stop pending T3-rtx and heartbeat timers */
+       sctp_add_cmd_sf(commands, SCTP_CMD_T3_RTX_TIMERS_STOP, SCTP_NULL());
+       sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_STOP, SCTP_NULL());
+
+       /* Delete non-primary peer ip addresses since we are transitioning
+        * back to the COOKIE-WAIT state
+        */
+       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 
+        */
+       sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, 
+                       SCTP_TRANSPORT(asoc->peer.primary_path));
+
        /* Cast away the const modifier, as we want to just
         * rerun it through as a sideffect.
         */
        sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_INC,
                        SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR));
 
-       /* If we've sent any data bundled with COOKIE-ECHO we need to
-        * resend.
-        */
-       list_for_each(pos, &asoc->peer.transport_addr_list) {
-               t = list_entry(pos, struct sctp_transport, transports);
-               sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(t));
-       }
-
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
@@ -1993,16 +2216,28 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify_either(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-       /* Check that chunk header looks valid.  */
+       /* Make sure that the ABORT chunk has a valid length.
+        * Since this is an ABORT chunk, we have to discard it
+        * because of the following text:
+        * RFC 2960, Section 3.3.7
+        *    If an endpoint receives an ABORT with a format error or for an
+        *    association that doesn't exist, it MUST silently discard it.
+        * Becasue the length is "invalid", we can't really discard just
+        * as we do not know its true length.  So, to be safe, discard the
+        * packet.
+        */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+       /* 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_INC_STATS(SctpAborteds);
-       SCTP_DEC_STATS(SctpCurrEstab);
+       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
 
        return SCTP_DISPOSITION_ABORT;
 }
@@ -2025,27 +2260,43 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify_either(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
-                       SCTP_STATE(SCTP_STATE_CLOSED));
-       SCTP_INC_STATS(SctpAborteds);
-       sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
-                       SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+       /* Make sure that the ABORT chunk has a valid length.
+        * Since this is an ABORT chunk, we have to discard it
+        * because of the following text:
+        * RFC 2960, Section 3.3.7
+        *    If an endpoint receives an ABORT with a format error or for an
+        *    association that doesn't exist, it MUST silently discard it.
+        * Becasue the length is "invalid", we can't really discard just
+        * as we do not know its true length.  So, to be safe, discard the
+        * packet.
+        */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-       /* Check that chunk header looks valid.  */
+       /* 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;
 
-       /* CMD_INIT_FAILED will DELETE_TCB. */
-       sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(error));
-
+       sctp_stop_t1_and_abort(commands, error);
        return SCTP_DISPOSITION_ABORT;
 }
 
+/*
+ * Process an incoming ICMP as an ABORT.  (COOKIE-WAIT state)
+ */
+sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(const struct sctp_endpoint *ep,
+                                       const struct sctp_association *asoc,
+                                       const sctp_subtype_t type,
+                                       void *arg,
+                                       sctp_cmd_seq_t *commands)
+{
+       sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR);
+       return SCTP_DISPOSITION_ABORT;
+}
+
 /*
  * Process an ABORT.  (COOKIE-ECHOED state)
- *
- * See sctp_sf_do_9_1_abort() above.
  */
 sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
                                               const struct sctp_association *asoc,
@@ -2059,6 +2310,23 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
        return sctp_sf_cookie_wait_abort(ep, asoc, type, arg, commands);
 }
 
+/*
+ * Stop T1 timer and abort association with "INIT failed".
+ *
+ * This is common code called by several sctp_sf_*_abort() functions above.
+ */
+void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error)
+{
+       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_TIMER_STOP,
+                       SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+       /* CMD_INIT_FAILED will DELETE_TCB. */
+       sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
+                       SCTP_U32(error));
+}
+
 /*
  * sctp_sf_do_9_2_shut
  *
@@ -2103,14 +2371,20 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
        sctp_disposition_t disposition;
        struct sctp_ulpevent *ev;
 
+       if (!sctp_vtag_verify(chunk, asoc))
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+       /* Make sure that the SHUTDOWN chunk has a valid length. */
+       if (!sctp_chunk_length_valid(chunk,
+                                     sizeof(struct sctp_shutdown_chunk_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        /* Convert the elaborate header.  */
        sdh = (sctp_shutdownhdr_t *)chunk->skb->data;
        skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t));
        chunk->subh.shutdown_hdr = sdh;
 
-       if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-
        /* Upon the reception of the SHUTDOWN, the peer endpoint shall
         *  - enter the SHUTDOWN-RECEIVED state,
         *  - stop accepting new data from its SCTP user
@@ -2167,6 +2441,10 @@ 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;
 
+       /* Since we are not going to really process this INIT, there
+        * is no point in verifying chunk boundries.  Just generate
+        * the SHUTDOWN ACK.
+        */
        reply = sctp_make_shutdown_ack(asoc, chunk);
        if (NULL == reply)
                goto nomem;
@@ -2224,6 +2502,10 @@ sctp_disposition_t sctp_sf_do_ecn_cwr(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       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));
 
@@ -2274,6 +2556,10 @@ sctp_disposition_t sctp_sf_do_ecne(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_ecne_chunk_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        ecne = (sctp_ecnehdr_t *) chunk->skb->data;
        skb_pull(chunk->skb, sizeof(sctp_ecnehdr_t));
 
@@ -2321,12 +2607,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
                                        sctp_cmd_seq_t *commands)
 {
        struct sctp_chunk *chunk = arg;
-       sctp_datahdr_t *data_hdr;
-       struct sctp_chunk *err;
-       size_t datalen;
-       sctp_verb_t deliver;
-       int tmp;
-       __u32 tsn;
+       int error;
 
        if (!sctp_vtag_verify(chunk, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
@@ -2334,224 +2615,95 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
         }
 
-       data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data;
-       skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
 
-       tsn = ntohl(data_hdr->tsn);
-       SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn);
+       error = sctp_eat_data(asoc, chunk, commands );
+       switch (error) {
+       case SCTP_IERROR_NO_ERROR:
+               break;
+       case SCTP_IERROR_HIGH_TSN:
+       case SCTP_IERROR_BAD_STREAM:
+               goto discard_noforce;
+       case SCTP_IERROR_DUP_TSN:
+       case SCTP_IERROR_IGNORE_TSN:
+               goto discard_force;
+       case SCTP_IERROR_NO_DATA:
+               goto consume;
+       default:
+               BUG();
+       }
 
-       /* ASSERT:  Now skb->data is really the user data.  */
+       if (asoc->autoclose) {
+               sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
+                               SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
+       }
 
-       /* Process ECN based congestion.
+       /* If this is the last chunk in a packet, we need to count it
+        * toward sack generation.  Note that we need to SACK every
+        * OTHER packet containing data chunks, EVEN IF WE DISCARD
+        * THEM.  We elect to NOT generate SACK's if the chunk fails
+        * the verification tag test.
         *
-        * Since the chunk structure is reused for all chunks within
-        * a packet, we use ecn_ce_done to track if we've already
-        * done CE processing for this packet.
+        * RFC 2960 6.2 Acknowledgement on Reception of DATA Chunks
         *
-        * We need to do ECN processing even if we plan to discard the
-        * chunk later.
+        * The SCTP endpoint MUST always acknowledge the reception of
+        * each valid DATA chunk.
+        *
+        * The guidelines on delayed acknowledgement algorithm
+        * specified in  Section 4.2 of [RFC2581] SHOULD be followed.
+        * Specifically, an acknowledgement SHOULD be generated for at
+        * least every second packet (not every second DATA chunk)
+        * received, and SHOULD be generated within 200 ms of the
+        * arrival of any unacknowledged DATA chunk.  In some
+        * situations it may be beneficial for an SCTP transmitter to
+        * be more conservative than the algorithms detailed in this
+        * document allow. However, an SCTP transmitter MUST NOT be
+        * more aggressive than the following algorithms allow.
         */
+       if (chunk->end_of_packet) {
+               sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE());
 
-       if (!chunk->ecn_ce_done) {
-               struct sctp_af *af;
-               chunk->ecn_ce_done = 1;
-
-               af = sctp_get_af_specific(
-                       ipver2af(chunk->skb->nh.iph->version));
-
-               if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
-                       /* Do real work as sideffect. */
-                       sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
-                                       SCTP_U32(tsn));
-               }
-       }
-
-       tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn);
-       if (tmp < 0) {
-               /* The TSN is too high--silently discard the chunk and
-                * count on it getting retransmitted later.
-                */
-               goto discard_noforce;
-       } else if (tmp > 0) {
-               /* This is a duplicate.  Record it.  */
-               sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn));
-               goto discard_force;
+               /* Start the SACK timer.  */
+               sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
+                               SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
        }
 
-       /* This is a new TSN.  */
+       return SCTP_DISPOSITION_CONSUME;
 
-       /* Discard if there is no room in the receive window.
-        * Actually, allow a little bit of overflow (up to a MTU).
+discard_force:
+       /* RFC 2960 6.2 Acknowledgement on Reception of DATA Chunks
+        *
+        * When a packet arrives with duplicate DATA chunk(s) and with
+        * no new DATA chunk(s), the endpoint MUST immediately send a
+        * SACK with no delay.  If a packet arrives with duplicate
+        * DATA chunk(s) bundled with new DATA chunks, the endpoint
+        * MAY immediately send a SACK.  Normally receipt of duplicate
+        * DATA chunks will occur when the original SACK chunk was lost
+        * and the peer's RTO has expired.  The duplicate TSN number(s)
+        * SHOULD be reported in the SACK as duplicate.
         */
-       datalen = ntohs(chunk->chunk_hdr->length);
-       datalen -= sizeof(sctp_data_chunk_t);
-
-       deliver = SCTP_CMD_CHUNK_ULP;
+       /* In our case, we split the MAY SACK advice up whether or not
+        * the last chunk is a duplicate.'
+        */
+       if (chunk->end_of_packet)
+               sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE());
+       return SCTP_DISPOSITION_DISCARD;
 
-       /* Think about partial delivery. */
-       if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) {
+discard_noforce:
+       if (chunk->end_of_packet) {
+               sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE());
 
-               /* Even if we don't accept this chunk there is
-                * memory pressure.
-                */
-               sctp_add_cmd_sf(commands, SCTP_CMD_PART_DELIVER, SCTP_NULL());
+               /* Start the SACK timer.  */
+               sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
+                               SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
        }
-
-        /* 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 this is the next TSN, consider reneging to make
-                * room.   Note: Playing nice with a confused sender.  A
-                * malicious sender can still eat up all our buffer
-                * 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) {
-                       SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn);
-                       deliver = SCTP_CMD_RENEGE;
-               } else {
-                       SCTP_DEBUG_PRINTK("Discard tsn: %u len: %Zd, "
-                                         "rwnd: %d\n", tsn, datalen,
-                                         asoc->rwnd);
-                       goto discard_force;
-               }
-       }
-
-       /*
-        * Section 3.3.10.9 No User Data (9)
-        *
-        * Cause of error
-        * ---------------
-        * No User Data:  This error cause is returned to the originator of a
-        * DATA chunk if a received DATA chunk has no user data.
-        */
-       if (unlikely(0 == datalen)) {
-               err = sctp_make_abort_no_data(asoc, chunk, tsn);
-               if (err) {
-                       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-                                       SCTP_CHUNK(err));
-               }
-               /* We are going to ABORT, so we might as well stop
-                * 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_ASSOC_FAILED,
-                               SCTP_U32(SCTP_ERROR_NO_DATA));
-               SCTP_INC_STATS(SctpAborteds);
-               SCTP_DEC_STATS(SctpCurrEstab);
-               return SCTP_DISPOSITION_CONSUME;
-       }
-
-       /* If definately accepting the DATA chunk, record its TSN, otherwise
-        * wait for renege processing.
-        */
-       if (SCTP_CMD_CHUNK_ULP == deliver)
-               sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
-
-       /* Note: Some chunks may get overcounted (if we drop) or overcounted
-        * if we renege and the chunk arrives again.
-        */
-       if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
-               SCTP_INC_STATS(SctpInUnorderChunks);
-       else
-               SCTP_INC_STATS(SctpInOrderChunks);
-
-       /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
-        *
-        * If an endpoint receive a DATA chunk with an invalid stream
-        * identifier, it shall acknowledge the reception of the DATA chunk
-        * following the normal procedure, immediately send an ERROR chunk
-        * with cause set to "Invalid Stream Identifier" (See Section 3.3.10)
-        * and discard the DATA chunk.
-        */
-       if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) {
-               err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM,
-                                        &data_hdr->stream,
-                                        sizeof(data_hdr->stream));
-               if (err)
-                       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-                                       SCTP_CHUNK(err));
-               goto discard_noforce;
-       }
-
-       /* Send the data up to the user.  Note:  Schedule  the
-        * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK
-        * chunk needs the updated rwnd.
-        */
-       sctp_add_cmd_sf(commands, deliver, SCTP_CHUNK(chunk));
-
-       if (asoc->autoclose) {
-               sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
-                               SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
-       }
-
-       /* If this is the last chunk in a packet, we need to count it
-        * toward sack generation.  Note that we need to SACK every
-        * OTHER packet containing data chunks, EVEN IF WE DISCARD
-        * THEM.  We elect to NOT generate SACK's if the chunk fails
-        * the verification tag test.
-        *
-        * RFC 2960 6.2 Acknowledgement on Reception of DATA Chunks
-        *
-        * The SCTP endpoint MUST always acknowledge the reception of
-        * each valid DATA chunk.
-        *
-        * The guidelines on delayed acknowledgement algorithm
-        * specified in  Section 4.2 of [RFC2581] SHOULD be followed.
-        * Specifically, an acknowledgement SHOULD be generated for at
-        * least every second packet (not every second DATA chunk)
-        * received, and SHOULD be generated within 200 ms of the
-        * arrival of any unacknowledged DATA chunk.  In some
-        * situations it may be beneficial for an SCTP transmitter to
-        * be more conservative than the algorithms detailed in this
-        * document allow. However, an SCTP transmitter MUST NOT be
-        * more aggressive than the following algorithms allow.
-        */
-       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:
-       /* RFC 2960 6.2 Acknowledgement on Reception of DATA Chunks
-        *
-        * When a packet arrives with duplicate DATA chunk(s) and with
-        * no new DATA chunk(s), the endpoint MUST immediately send a
-        * SACK with no delay.  If a packet arrives with duplicate
-        * DATA chunk(s) bundled with new DATA chunks, the endpoint
-        * MAY immediately send a SACK.  Normally receipt of duplicate
-        * DATA chunks will occur when the original SACK chunk was lost
-        * and the peer's RTO has expired.  The duplicate TSN number(s)
-        * SHOULD be reported in the SACK as duplicate.
-        */
-       /* In our case, we split the MAY SACK advice up whether or not
-        * the last chunk is a duplicate.'
-        */
-       if (chunk->end_of_packet)
-               sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE());
-       return SCTP_DISPOSITION_DISCARD;
-
-discard_noforce:
-       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;
-}
+       return SCTP_DISPOSITION_DISCARD;
+consume:
+       return SCTP_DISPOSITION_CONSUME;
+       
+}
 
 /*
  * sctp_sf_eat_data_fast_4_4
@@ -2576,11 +2728,7 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep,
                                     sctp_cmd_seq_t *commands)
 {
        struct sctp_chunk *chunk = arg;
-       sctp_datahdr_t *data_hdr;
-       struct sctp_chunk *err;
-       size_t datalen;
-       int tmp;
-       __u32 tsn;
+       int error;
 
        if (!sctp_vtag_verify(chunk, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
@@ -2588,110 +2736,26 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep,
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
        }
 
-       data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *) chunk->skb->data;
-       skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
-
-       tsn = ntohl(data_hdr->tsn);
-
-       SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn);
-
-       /* ASSERT:  Now skb->data is really the user data.  */
-
-       /* Process ECN based congestion.
-        *
-        * Since the chunk structure is reused for all chunks within
-        * a packet, we use ecn_ce_done to track if we've already
-        * done CE processing for this packet.
-        *
-        * We need to do ECN processing even if we plan to discard the
-        * chunk later.
-        */
-       if (!chunk->ecn_ce_done) {
-               struct sctp_af *af;
-               chunk->ecn_ce_done = 1;
-
-               af = sctp_get_af_specific(
-                       ipver2af(chunk->skb->nh.iph->version));
-
-               if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
-                       /* Do real work as sideffect. */
-                       sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
-                                       SCTP_U32(tsn));
-               }
-       }
-
-       tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn);
-       if (tmp < 0) {
-               /* The TSN is too high--silently discard the chunk and
-                * count on it getting retransmitted later.
-                */
-               goto gen_shutdown;
-       } else if (tmp > 0) {
-               /* This is a duplicate.  Record it.  */
-               sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn));
-               goto gen_shutdown;
-       }
-
-       /* This is a new TSN.  */
-
-       datalen = ntohs(chunk->chunk_hdr->length);
-       datalen -= sizeof(sctp_data_chunk_t);
-
-       /*
-        * Section 3.3.10.9 No User Data (9)
-        *
-        * Cause of error
-        * ---------------
-        * No User Data:  This error cause is returned to the originator of a
-        * DATA chunk if a received DATA chunk has no user data.
-        */
-       if (unlikely(0 == datalen)) {
-               err = sctp_make_abort_no_data(asoc, chunk, tsn);
-               if (err) {
-                       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-                                       SCTP_CHUNK(err));
-               }
-               /* We are going to ABORT, so we might as well stop
-                * 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_ASSOC_FAILED,
-                               SCTP_U32(SCTP_ERROR_NO_DATA));
-               SCTP_INC_STATS(SctpAborteds);
-               SCTP_DEC_STATS(SctpCurrEstab);
-               return SCTP_DISPOSITION_CONSUME;
-       }
-
-       /* We are accepting this DATA chunk. */
-
-       /* Record the fact that we have received this TSN.  */
-       sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
-
-       if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
-               SCTP_INC_STATS(SctpInUnorderChunks);
-       else
-               SCTP_INC_STATS(SctpInOrderChunks);
-
-       /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
-        *
-        * If an endpoint receive a DATA chunk with an invalid stream
-        * identifier, it shall acknowledge the reception of the DATA chunk
-        * following the normal procedure, immediately send an ERROR chunk
-        * with cause set to "Invalid Stream Identifier" (See Section 3.3.10)
-        * and discard the DATA chunk.
-        */
-       if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) {
-               err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM,
-                                        &data_hdr->stream,
-                                        sizeof(data_hdr->stream));
-               if (err) {
-                       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-                                       SCTP_CHUNK(err));
-               }
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
+       error = sctp_eat_data(asoc, chunk, commands );
+       switch (error) {
+       case SCTP_IERROR_NO_ERROR:
+       case SCTP_IERROR_HIGH_TSN:
+       case SCTP_IERROR_DUP_TSN:
+       case SCTP_IERROR_IGNORE_TSN:
+       case SCTP_IERROR_BAD_STREAM:
+               break;
+       case SCTP_IERROR_NO_DATA:
+               goto consume;
+       default:
+               BUG();
        }
 
        /* Go a head and force a SACK, since we are shutting down. */
-gen_shutdown:
+
        /* Implementor's Guide.
         *
         * While in SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately
@@ -2707,6 +2771,8 @@ gen_shutdown:
                sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
                                SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
        }
+
+consume:
        return SCTP_DISPOSITION_CONSUME;
 }
 
@@ -2755,6 +2821,11 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* Make sure that the SACK chunk has a valid length. */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_sack_chunk_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        /* Pull the SACK chunk from the data buffer */
        sackh = sctp_sm_pull_sack(chunk);
        /* Was this a bogus SACK? */
@@ -2832,7 +2903,7 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                SCTP_PACKET(packet));
 
-               SCTP_INC_STATS(SctpOutCtrlChunks);
+               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
 
                return SCTP_DISPOSITION_CONSUME;
        }
@@ -2857,6 +2928,14 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
        struct sctp_chunk *chunk = arg;
        struct sctp_ulpevent *ev;
 
+       if (!sctp_vtag_verify(chunk, asoc))
+               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+       /* Make sure that the ERROR chunk has a valid length. */
+       if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        while (chunk->chunk_end > chunk->skb->data) {
                ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
                                                     GFP_ATOMIC);
@@ -2901,6 +2980,11 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* 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);
+
        /* 10.2 H) SHUTDOWN COMPLETE notification
         *
         * When SCTP completes the shutdown procedures (section 9.2) this
@@ -2929,8 +3013,8 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
 
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
-       SCTP_INC_STATS(SctpShutdowns);
-       SCTP_DEC_STATS(SctpCurrEstab);
+       SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS);
+       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
 
        /* ...and remove all record of the association. */
@@ -2971,15 +3055,27 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
        __u8 *ch_end;
        int ootb_shut_ack = 0;
 
-       SCTP_INC_STATS(SctpOutOfBlues);
+       SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES);
 
        ch = (sctp_chunkhdr_t *) chunk->chunk_hdr;
        do {
+               /* Break out if chunk length is less then minimal. */
+               if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
+                       break;
+
                ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
 
                if (SCTP_CID_SHUTDOWN_ACK == ch->type)
                        ootb_shut_ack = 1;
 
+               /* RFC 2960, Section 3.3.7
+                *   Moreover, under any circumstances, an endpoint that
+                *   receives an ABORT  MUST NOT respond to that ABORT by
+                *   sending an ABORT of its own.
+                */
+               if (SCTP_CID_ABORT == ch->type)
+                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       
                ch = (sctp_chunkhdr_t *) ch_end;
        } while (ch_end < skb->tail);
 
@@ -3010,11 +3106,11 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_shut_8_4_5(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_shut_8_4_5(const struct sctp_endpoint *ep,
+                                            const struct sctp_association *asoc,
+                                            const sctp_subtype_t type,
+                                            void *arg,
+                                            sctp_cmd_seq_t *commands)
 {
        struct sctp_packet *packet = NULL;
        struct sctp_chunk *chunk = arg;
@@ -3040,7 +3136,13 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                SCTP_PACKET(packet));
 
-               SCTP_INC_STATS(SctpOutCtrlChunks);
+               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+
+               /* If the chunk length is invalid, we don't want to process
+                * the reset of the packet.
+                */
+               if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
+                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
                return SCTP_DISPOSITION_CONSUME;
        }
@@ -3084,6 +3186,17 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
        sctp_addiphdr_t         *hdr;
        __u32                   serial;
 
+       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 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,
+                                                 commands);
+
        hdr = (sctp_addiphdr_t *)chunk->skb->data;
        serial = ntohl(hdr->serial);
 
@@ -3104,7 +3217,8 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
                /* 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
+                * 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.
                 */
                if (asoc->addip_last_asconf_ack)
@@ -3143,6 +3257,17 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
        sctp_addiphdr_t         *addip_hdr;
        __u32                   sent_serial, rcvd_serial;
 
+       if (!sctp_vtag_verify(asconf_ack, 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 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,
+                                                 commands);
+
        addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data;
        rcvd_serial = ntohl(addip_hdr->serial);
 
@@ -3176,8 +3301,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
                sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_U32(SCTP_ERROR_ASCONF_ACK));
-               SCTP_INC_STATS(SctpAborteds);
-               SCTP_DEC_STATS(SctpCurrEstab);
+               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_ABORT;
        }
 
@@ -3202,8 +3327,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
                sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_U32(SCTP_ERROR_ASCONF_ACK));
-               SCTP_INC_STATS(SctpAborteds);
-               SCTP_DEC_STATS(SctpCurrEstab);
+               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_ABORT;
        }
 
@@ -3241,6 +3366,11 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
        }
 
+       /* Make sure that the FORWARD_TSN chunk has valid length.  */
+       if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_fwdtsn_chunk)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
        chunk->subh.fwdtsn_hdr = fwdtsn_hdr;
        len = ntohs(chunk->chunk_hdr->length);
@@ -3299,6 +3429,11 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
        }
 
+       /* Make sure that the FORWARD_TSN chunk has a valid length.  */
+       if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_fwdtsn_chunk)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
        chunk->subh.fwdtsn_hdr = fwdtsn_hdr;
        len = ntohs(chunk->chunk_hdr->length);
@@ -3373,6 +3508,14 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(unk_chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+       /* 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(unk_chunk, sizeof(sctp_chunkhdr_t)))
+               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                 commands);
+
        switch (type.chunk & SCTP_CID_ACTION_MASK) {
        case SCTP_CID_ACTION_DISCARD:
                /* Discard the packet.  */
@@ -3495,6 +3638,66 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
        return SCTP_DISPOSITION_VIOLATION;
 }
 
+
+/*
+ * Handle a protocol violation when the chunk length is invalid.
+ * "Invalid" length is identified as smaller then the minimal length a
+ * given chunk can be.  For example, a SACK chunk has invalid length
+ * 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. 
+ *
+ * Section: Not specified
+ * Verification Tag:  Nothing to do
+ * Inputs
+ * (endpoint, asoc, chunk)
+ *
+ * Outputs
+ * (reply_msg, msg_up, counters)
+ *
+ * Generate an  ABORT chunk and terminate the association.
+ */
+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:";
+
+       /* 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);
+
+       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);
+       }
+
+       sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
+
+       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+       
+       return SCTP_DISPOSITION_ABORT;
+
+nomem:
+       return SCTP_DISPOSITION_NOMEM;
+}
+
 /***************************************************************************
  * These are the state functions for handling primitive (Section 10) events.
  ***************************************************************************/
@@ -3797,8 +4000,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(
        sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                        SCTP_U32(SCTP_ERROR_USER_ABORT));
 
-       SCTP_INC_STATS(SctpAborteds);
-       SCTP_DEC_STATS(SctpCurrEstab);
+       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
 
        return retval;
 }
@@ -3855,7 +4058,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
 
-       SCTP_INC_STATS(SctpShutdowns);
+       SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS);
 
        sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
 
@@ -3928,7 +4131,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
 
-       SCTP_INC_STATS(SctpAborteds);
+       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
 
        /* Even if we can't send the ABORT due to low memory delete the
         * TCB.  This is a departure from our typical NOMEM handling.
@@ -4207,6 +4410,23 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(
        struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
        struct sctp_chunk *reply;
 
+       /* There are 2 ways of getting here:
+        *    1) called in response to a SHUTDOWN chunk
+        *    2) called when SCTP_EVENT_NO_PENDING_TSN event is issued.
+        *
+        * For the case (2), the arg parameter is set to NULL.  We need
+        * to check that we have a chunk before accessing it's fields.
+        */
+       if (chunk) {
+               if (!sctp_vtag_verify(chunk, asoc))
+                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+
+               /* Make sure that the SHUTDOWN chunk has a valid length. */
+               if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_shutdown_chunk_t)))
+                       return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                                                         commands);
+       }
+
        /* If it has no more outstanding DATA chunks, the SHUTDOWN receiver
         * shall send a SHUTDOWN ACK ...
         */
@@ -4288,8 +4508,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
                /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_U32(SCTP_ERROR_NO_ERROR));
-               SCTP_INC_STATS(SctpAborteds);
-               SCTP_DEC_STATS(SctpCurrEstab);
+               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_DELETE_TCB;
        }
 
@@ -4458,8 +4678,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
                /* Note:  CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_U32(SCTP_ERROR_NO_ERROR));
-               SCTP_INC_STATS(SctpAborteds);
-               SCTP_DEC_STATS(SctpCurrEstab);
+               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_DELETE_TCB;
        }
 
@@ -4532,8 +4752,8 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
                                SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_U32(SCTP_ERROR_NO_ERROR));
-               SCTP_INC_STATS(SctpAborteds);
-               SCTP_INC_STATS(SctpCurrEstab);
+               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+               SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_ABORT;
        }
 
@@ -4694,7 +4914,7 @@ sctp_disposition_t sctp_sf_timer_ignore(const struct sctp_endpoint *ep,
  ********************************************************************/
 
 /* Pull the SACK chunk based on the SACK header. */
-struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
+static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
 {
        struct sctp_sackhdr *sack;
        unsigned int len;
@@ -4709,7 +4929,7 @@ struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
        num_blocks = ntohs(sack->num_gap_ack_blocks);
        num_dup_tsns = ntohs(sack->num_dup_tsns);
        len = sizeof(struct sctp_sackhdr);
-       len = (num_blocks + num_dup_tsns) * sizeof(__u32);
+       len += (num_blocks + num_dup_tsns) * sizeof(__u32);
        if (len > chunk->skb->len)
                return NULL;
 
@@ -4721,7 +4941,7 @@ struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
 /* Create an ABORT packet to be sent as a response, with the specified
  * error causes.
  */
-struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
+static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
                                  const struct sctp_association *asoc,
                                  struct sctp_chunk *chunk,
                                  const void *payload,
@@ -4757,8 +4977,8 @@ struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
 }
 
 /* Allocate a packet for responding in the OOTB conditions.  */
-struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
-                                const struct sctp_chunk *chunk)
+static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
+                                            const struct sctp_chunk *chunk)
 {
        struct sctp_packet *packet;
        struct sctp_transport *transport;
@@ -4821,11 +5041,11 @@ void sctp_ootb_pkt_free(struct sctp_packet *packet)
 }
 
 /* Send a stale cookie error when a invalid COOKIE ECHO chunk is found  */
-void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
-                               const struct sctp_association *asoc,
-                               const struct sctp_chunk *chunk,
-                               sctp_cmd_seq_t *commands,
-                               struct sctp_chunk *err_chunk)
+static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
+                                      const struct sctp_association *asoc,
+                                      const struct sctp_chunk *chunk,
+                                      sctp_cmd_seq_t *commands,
+                                      struct sctp_chunk *err_chunk)
 {
        struct sctp_packet *packet;
 
@@ -4843,8 +5063,176 @@ void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
                        sctp_packet_append_chunk(packet, err_chunk);
                        sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                        SCTP_PACKET(packet));
-                       SCTP_INC_STATS(SctpOutCtrlChunks);
+                       SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
                } else
                        sctp_chunk_free (err_chunk);
        }
 }
+
+
+/* Process a data chunk */
+static int sctp_eat_data(const struct sctp_association *asoc,
+                        struct sctp_chunk *chunk,
+                        sctp_cmd_seq_t *commands)
+{
+       sctp_datahdr_t *data_hdr;
+       struct sctp_chunk *err;
+       size_t datalen;
+       sctp_verb_t deliver;
+       int tmp;
+       __u32 tsn;
+
+       data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data;
+       skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
+
+       tsn = ntohl(data_hdr->tsn);
+       SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn);
+
+       /* ASSERT:  Now skb->data is really the user data.  */
+
+       /* Process ECN based congestion.
+        *
+        * Since the chunk structure is reused for all chunks within
+        * a packet, we use ecn_ce_done to track if we've already
+        * done CE processing for this packet.
+        *
+        * We need to do ECN processing even if we plan to discard the
+        * chunk later.
+        */
+
+       if (!chunk->ecn_ce_done) {
+               struct sctp_af *af;
+               chunk->ecn_ce_done = 1;
+
+               af = sctp_get_af_specific(
+                       ipver2af(chunk->skb->nh.iph->version));
+
+               if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
+                       /* Do real work as sideffect. */
+                       sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
+                                       SCTP_U32(tsn));
+               }
+       }
+
+       tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn);
+       if (tmp < 0) {
+               /* The TSN is too high--silently discard the chunk and
+                * count on it getting retransmitted later.
+                */
+               return SCTP_IERROR_HIGH_TSN;
+       } else if (tmp > 0) {
+               /* This is a duplicate.  Record it.  */
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn));
+               return SCTP_IERROR_DUP_TSN;
+       }
+
+       /* This is a new TSN.  */
+
+       /* Discard if there is no room in the receive window.
+        * Actually, allow a little bit of overflow (up to a MTU).
+        */
+       datalen = ntohs(chunk->chunk_hdr->length);
+       datalen -= sizeof(sctp_data_chunk_t);
+
+       deliver = SCTP_CMD_CHUNK_ULP;
+
+       /* Think about partial delivery. */
+       if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) {
+
+               /* Even if we don't accept this chunk there is
+                * memory pressure.
+                */
+               sctp_add_cmd_sf(commands, SCTP_CMD_PART_DELIVER, SCTP_NULL());
+       }
+
+        /* 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 this is the next TSN, consider reneging to make
+                * room.   Note: Playing nice with a confused sender.  A
+                * malicious sender can still eat up all our buffer
+                * 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) {
+                       SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn);
+                       deliver = SCTP_CMD_RENEGE;
+               } else {
+                       SCTP_DEBUG_PRINTK("Discard tsn: %u len: %Zd, "
+                                         "rwnd: %d\n", tsn, datalen,
+                                         asoc->rwnd);
+                       return SCTP_IERROR_IGNORE_TSN;
+               }
+       }
+
+       /*
+        * Section 3.3.10.9 No User Data (9)
+        *
+        * Cause of error
+        * ---------------
+        * No User Data:  This error cause is returned to the originator of a
+        * DATA chunk if a received DATA chunk has no user data.
+        */
+       if (unlikely(0 == datalen)) {
+               err = sctp_make_abort_no_data(asoc, chunk, tsn);
+               if (err) {
+                       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
+                                       SCTP_CHUNK(err));
+               }
+               /* We are going to ABORT, so we might as well stop
+                * 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_ASSOC_FAILED,
+                               SCTP_U32(SCTP_ERROR_NO_DATA));
+               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+               return SCTP_IERROR_NO_DATA;
+       }
+
+       /* If definately accepting the DATA chunk, record its TSN, otherwise
+        * wait for renege processing.
+        */
+       if (SCTP_CMD_CHUNK_ULP == deliver)
+               sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
+
+       /* Note: Some chunks may get overcounted (if we drop) or overcounted
+        * if we renege and the chunk arrives again.
+        */
+       if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
+               SCTP_INC_STATS(SCTP_MIB_INUNORDERCHUNKS);
+       else
+               SCTP_INC_STATS(SCTP_MIB_INORDERCHUNKS);
+
+       /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
+        *
+        * If an endpoint receive a DATA chunk with an invalid stream
+        * identifier, it shall acknowledge the reception of the DATA chunk
+        * following the normal procedure, immediately send an ERROR chunk
+        * with cause set to "Invalid Stream Identifier" (See Section 3.3.10)
+        * and discard the DATA chunk.
+        */
+       if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) {
+               err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM,
+                                        &data_hdr->stream,
+                                        sizeof(data_hdr->stream));
+               if (err)
+                       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
+                                       SCTP_CHUNK(err));
+               return SCTP_IERROR_BAD_STREAM;
+       }
+
+       /* Send the data up to the user.  Note:  Schedule  the
+        * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK
+        * chunk needs the updated rwnd.
+        */
+       sctp_add_cmd_sf(commands, deliver, SCTP_CHUNK(chunk));
+
+       return SCTP_IERROR_NO_ERROR;
+}