sctp: Follow security requirement of responding with 1 packet
[pandora-kernel.git] / net / sctp / sm_statefuns.c
index f986587..b66a41d 100644 (file)
@@ -1,23 +1,21 @@
-/* SCTP kernel reference Implementation
+/* SCTP kernel implementation
  * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001-2002 Intel Corp.
  * Copyright (c) 2002      Nokia Corp.
  *
- * This file is part of the SCTP kernel reference Implementation
- *
- * This is part of the SCTP Linux Kernel Reference Implementation.
+ * This is part of the SCTP Linux Kernel Implementation.
  *
  * These are the state functions for the state machine.
  *
- * The SCTP reference implementation is free software;
+ * This SCTP implementation is free software;
  * you can redistribute it and/or modify it under the terms of
  * the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * any later version.
  *
- * The SCTP reference implementation is distributed in the hope that it
+ * This SCTP implementation is distributed in the hope that it
  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  *                 ************************
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
@@ -797,8 +795,6 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
                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));
 
@@ -885,7 +881,6 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
        if (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());
 
        /* It may also notify its ULP about the successful
         * establishment of the association with a Communication Up
@@ -1126,7 +1121,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
                                printk(KERN_WARNING
                                    "%s association %p could not find address "
                                    NIP6_FMT "\n",
-                                   __FUNCTION__,
+                                   __func__,
                                    asoc,
                                    NIP6(from_addr.v6.sin6_addr));
                } else {
@@ -1134,7 +1129,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
                                printk(KERN_WARNING
                                    "%s association %p could not find address "
                                    NIPQUAD_FMT "\n",
-                                   __FUNCTION__,
+                                   __func__,
                                    asoc,
                                    NIPQUAD(from_addr.v4.sin_addr.s_addr));
                }
@@ -1152,7 +1147,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
            time_after(jiffies, hbinfo->sent_at + max_interval)) {
                SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp "
                                  "received for transport: %p\n",
-                                  __FUNCTION__, link);
+                                  __func__, link);
                return SCTP_DISPOSITION_DISCARD;
        }
 
@@ -1228,7 +1223,6 @@ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc,
                                       sctp_cmd_seq_t *commands)
 {
        struct sctp_transport *new_addr, *addr;
-       struct list_head *pos, *pos2;
        int found;
 
        /* Implementor's Guide - Sectin 5.2.2
@@ -1245,12 +1239,11 @@ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc,
        new_addr = NULL;
        found = 0;
 
-       list_for_each(pos, &new_asoc->peer.transport_addr_list) {
-               new_addr = list_entry(pos, struct sctp_transport, transports);
+       list_for_each_entry(new_addr, &new_asoc->peer.transport_addr_list,
+                       transports) {
                found = 0;
-               list_for_each(pos2, &asoc->peer.transport_addr_list) {
-                       addr = list_entry(pos2, struct sctp_transport,
-                                         transports);
+               list_for_each_entry(addr, &asoc->peer.transport_addr_list,
+                               transports) {
                        if (sctp_cmp_addr_exact(&new_addr->ipaddr,
                                                &addr->ipaddr)) {
                                found = 1;
@@ -1785,7 +1778,6 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
                goto nomem;
 
        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
-       sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
 
        /* RFC 2960 5.1 Normal Establishment of an Association
         *
@@ -1902,12 +1894,13 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
 
                }
        }
-       sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
 
        repl = sctp_make_cookie_ack(new_asoc, chunk);
        if (!repl)
                goto nomem;
 
+       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
+
        if (ev)
                sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
                                SCTP_ULPEVENT(ev));
@@ -1915,9 +1908,6 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
                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:
@@ -3137,12 +3127,8 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
                if (!ev)
                        goto nomem;
 
-               if (!sctp_add_cmd(commands, SCTP_CMD_EVENT_ULP,
-                                 SCTP_ULPEVENT(ev))) {
-                       sctp_ulpevent_free(ev);
-                       goto nomem;
-               }
-
+               sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+                               SCTP_ULPEVENT(ev));
                sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR,
                                SCTP_CHUNK(chunk));
        }
@@ -3670,7 +3656,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
        skb_pull(chunk->skb, len);
 
        tsn = ntohl(fwdtsn_hdr->new_cum_tsn);
-       SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn);
+       SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __func__, tsn);
 
        /* The TSN is too high--silently discard the chunk and count on it
         * getting retransmitted later.
@@ -3730,7 +3716,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
        skb_pull(chunk->skb, len);
 
        tsn = ntohl(fwdtsn_hdr->new_cum_tsn);
-       SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn);
+       SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __func__, tsn);
 
        /* The TSN is too high--silently discard the chunk and count on it
         * getting retransmitted later.
@@ -3978,9 +3964,6 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
                break;
        case SCTP_CID_ACTION_DISCARD_ERR:
-               /* Discard the packet.  */
-               sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-
                /* Generate an ERROR chunk as response. */
                hdr = unk_chunk->chunk_hdr;
                err_chunk = sctp_make_op_error(asoc, unk_chunk,
@@ -3990,6 +3973,9 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
                        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
                                        SCTP_CHUNK(err_chunk));
                }
+
+               /* Discard the packet.  */
+               sctp_sf_pdiscard(ep, asoc, type, arg, commands);
                return SCTP_DISPOSITION_CONSUME;
                break;
        case SCTP_CID_ACTION_SKIP:
@@ -4146,6 +4132,24 @@ static sctp_disposition_t sctp_sf_abort_violation(
                goto nomem;
 
        if (asoc) {
+               /* Treat INIT-ACK as a special case during COOKIE-WAIT. */
+               if (chunk->chunk_hdr->type == SCTP_CID_INIT_ACK &&
+                   !asoc->peer.i.init_tag) {
+                       sctp_initack_chunk_t *initack;
+
+                       initack = (sctp_initack_chunk_t *)chunk->chunk_hdr;
+                       if (!sctp_chunk_length_valid(chunk,
+                                                    sizeof(sctp_initack_chunk_t)))
+                               abort->chunk_hdr->flags |= SCTP_CHUNK_FLAG_T;
+                       else {
+                               unsigned int inittag;
+
+                               inittag = ntohl(initack->init_hdr.init_tag);
+                               sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_INITTAG,
+                                               SCTP_U32(inittag));
+                       }
+               }
+
                sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
                SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
 
@@ -4221,7 +4225,7 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
                                     void *arg,
                                     sctp_cmd_seq_t *commands)
 {
-       char err_str[]="The following chunk had invalid length:";
+       static const char err_str[]="The following chunk had invalid length:";
 
        return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
                                        sizeof(err_str));
@@ -4238,7 +4242,7 @@ static sctp_disposition_t sctp_sf_violation_paramlen(
                                     const sctp_subtype_t type,
                                     void *arg,
                                     sctp_cmd_seq_t *commands) {
-       char err_str[] = "The following parameter had invalid length:";
+       static const char err_str[] = "The following parameter had invalid length:";
 
        return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
                                        sizeof(err_str));
@@ -4257,7 +4261,7 @@ static sctp_disposition_t sctp_sf_violation_ctsn(
                                     void *arg,
                                     sctp_cmd_seq_t *commands)
 {
-       char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:";
+       static const char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:";
 
        return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
                                        sizeof(err_str));
@@ -4276,7 +4280,7 @@ static sctp_disposition_t sctp_sf_violation_chunk(
                                     void *arg,
                                     sctp_cmd_seq_t *commands)
 {
-       char err_str[]="The following chunk violates protocol:";
+       static const char err_str[]="The following chunk violates protocol:";
 
        if (!asoc)
                return sctp_sf_violation(ep, asoc, type, arg, commands);
@@ -4351,6 +4355,7 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const struct sctp_endpoint *ep,
                                       sctp_cmd_seq_t *commands)
 {
        struct sctp_chunk *repl;
+       struct sctp_association* my_asoc;
 
        /* The comment below says that we enter COOKIE-WAIT AFTER
         * sending the INIT, but that doesn't actually work in our
@@ -4374,8 +4379,8 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const struct sctp_endpoint *ep,
        /* Cast away the const modifier, as we want to just
         * rerun it through as a sideffect.
         */
-       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC,
-                       SCTP_ASOC((struct sctp_association *) asoc));
+       my_asoc = (struct sctp_association *)asoc;
+       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(my_asoc));
 
        /* Choose transport for INIT. */
        sctp_add_cmd_sf(commands, SCTP_CMD_INIT_CHOOSE_TRANSPORT,
@@ -5314,6 +5319,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
        SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
        SCTP_INC_STATS(SCTP_MIB_T2_SHUTDOWN_EXPIREDS);
 
+       ((struct sctp_association *)asoc)->shutdown_retries++;
+
        if (asoc->overall_error_count >= asoc->max_retrans) {
                sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
                                SCTP_ERROR(ETIMEDOUT));