blob: 848a48229f17b5224bad8c452719a893f7cbbe1c [file] [log] [blame]
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines, Corp.
* 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.
*
* These are the state functions for the state machine.
*
* The SCTP reference 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
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to the
* email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
*
* Written or modified by:
* La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us>
* Mathew Kotowsky <kotowsky@sctp.org>
* Sridhar Samudrala <samudrala@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com>
* Hui Huang <hui.huang@nokia.com>
* Dajiang Zhang <dajiang.zhang@nokia.com>
* Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/net.h>
#include <linux/inet.h>
#include <net/sock.h>
#include <net/inet_ecn.h>
#include <linux/skbuff.h>
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
#include <net/sctp/structs.h>
/**********************************************************
* These are the state functions for handling chunk events.
**********************************************************/
/*
* Process the final SHUTDOWN COMPLETE.
*
* Section: 4 (C) (diagram), 9.2
* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint will verify
* that it is in SHUTDOWN-ACK-SENT state, if it is not the chunk should be
* discarded. If the endpoint is in the SHUTDOWN-ACK-SENT state the endpoint
* should stop the T2-shutdown timer and remove all knowledge of the
* association (and thus the association enters the CLOSED state).
*
* Verification Tag: 8.5.1(C)
* C) Rules for packet carrying SHUTDOWN COMPLETE:
* ...
* - The receiver of a SHUTDOWN COMPLETE shall accept the packet if the
* Verification Tag field of the packet matches its own tag OR it is
* set to its peer's tag and the T bit is set in the Chunk Flags.
* Otherwise, the receiver MUST silently discard the packet and take
* no further action. An endpoint MUST ignore the SHUTDOWN COMPLETE if
* it is not in the SHUTDOWN-ACK-SENT state.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_ulpevent_t *ev;
/* RFC 2960 6.10 Bundling
*
* An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks.
*/
if (!chunk->singleton)
return SCTP_DISPOSITION_VIOLATION;
if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* RFC 2960 10.2 SCTP-to-ULP
*
* H) SHUTDOWN COMPLETE notification
*
* When SCTP completes the shutdown procedures (section 9.2) this
* notification is passed to the upper layer.
*/
ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP,
0, 0, 0, GFP_ATOMIC);
if (!ev)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
/* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint
* will verify that it is in SHUTDOWN-ACK-SENT state, if it is
* not the chunk should be discarded. If the endpoint is in
* the SHUTDOWN-ACK-SENT state the endpoint should stop the
* T2-shutdown timer and remove all knowledge of the
* association (and thus the association enters the CLOSED
* state).
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* Respond to a normal INIT chunk.
* We are the side that is being asked for an association.
*
* Section: 5.1 Normal Establishment of an Association, B
* B) "Z" shall respond immediately with an INIT ACK chunk. The
* destination IP address of the INIT ACK MUST be set to the source
* IP address of the INIT to which this INIT ACK is responding. In
* the response, besides filling in other parameters, "Z" must set the
* Verification Tag field to Tag_A, and also provide its own
* Verification Tag (Tag_Z) in the Initiate Tag field.
*
* Verification Tag: No checking.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_chunk_t *repl;
sctp_association_t *new_asoc;
sctp_chunk_t *err_chunk;
sctp_packet_t *packet;
sctp_unrecognized_param_t *unk_param;
int len;
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond with an ABORT.
*/
if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
return sctp_sf_ootb(ep, asoc, type, arg, commands);
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks.
*/
if (!chunk->singleton)
return SCTP_DISPOSITION_VIOLATION;
/* Verify the INIT chunk before processing it. */
err_chunk = NULL;
if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
(sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
&err_chunk)) {
/* This chunk contains fatal error. It is to be discarded.
* Send an ABORT, with causes if there is any.
*/
if (err_chunk) {
packet = sctp_abort_pkt_new(ep, asoc, arg,
(__u8 *)(err_chunk->chunk_hdr) +
sizeof(sctp_chunkhdr_t),
ntohs(err_chunk->chunk_hdr->length) -
sizeof(sctp_chunkhdr_t));
sctp_free_chunk(err_chunk);
if (packet) {
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
SCTP_PACKET(packet));
return SCTP_DISPOSITION_CONSUME;
} else {
return SCTP_DISPOSITION_NOMEM;
}
} else {
return sctp_sf_tabort_8_4_8(ep, asoc, type, arg,
commands);
}
}
/* Grab the INIT header. */
chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data;
/* Tag the variable length parameters. */
chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t));
new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC);
if (!new_asoc)
goto nomem;
/* The call, sctp_process_init(), can fail on memory allocation. */
if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
sctp_source(chunk),
(sctp_init_chunk_t *)chunk->chunk_hdr,
GFP_ATOMIC))
goto nomem_init;
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
/* B) "Z" shall respond immediately with an INIT ACK chunk. */
/* If there are errors need to be reported for unknown parameters,
* make sure to reserve enough room in the INIT ACK for them.
*/
len = 0;
if (err_chunk)
len = ntohs(err_chunk->chunk_hdr->length) -
sizeof(sctp_chunkhdr_t);
if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0)
goto nomem_ack;
repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
if (!repl)
goto nomem_ack;
/* If there are errors need to be reported for unknown parameters,
* include them in the outgoing INIT ACK as "Unrecognized parameter"
* parameter.
*/
if (err_chunk) {
/* Get the "Unrecognized parameter" parameter(s) out of the
* ERROR chunk generated by sctp_verify_init(). Since the
* error cause code for "unknown parameter" and the
* "Unrecognized parameter" type is the same, we can
* construct the parameters in INIT ACK by copying the
* ERROR causes over.
*/
unk_param = (sctp_unrecognized_param_t *)
((__u8 *)(err_chunk->chunk_hdr) +
sizeof(sctp_chunkhdr_t));
/* Replace the cause code with the "Unrecognized parameter"
* parameter type.
*/
sctp_addto_chunk(repl, len, unk_param);
sctp_free_chunk(err_chunk);
}
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
/*
* Note: After sending out INIT ACK with the State Cookie parameter,
* "Z" MUST NOT allocate any resources, nor keep any states for the
* new association. Otherwise, "Z" will be vulnerable to resource
* attacks.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
nomem_ack:
if (err_chunk)
sctp_free_chunk(err_chunk);
nomem_init:
sctp_association_free(new_asoc);
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* Respond to a normal INIT ACK chunk.
* We are the side that is initiating the association.
*
* Section: 5.1 Normal Establishment of an Association, C
* C) Upon reception of the INIT ACK from "Z", "A" shall stop the T1-init
* timer and leave COOKIE-WAIT state. "A" shall then send the State
* Cookie received in the INIT ACK chunk in a COOKIE ECHO chunk, start
* the T1-cookie timer, and enter the COOKIE-ECHOED state.
*
* Note: The COOKIE ECHO chunk can be bundled with any pending outbound
* DATA chunks, but it MUST be the first chunk in the packet and
* until the COOKIE ACK is returned the sender MUST NOT send any
* other packets to the peer.
*
* Verification Tag: 3.3.3
* If the value of the Initiate Tag in a received INIT ACK chunk is
* found to be 0, the receiver MUST treat it as an error and close the
* association by transmitting an ABORT.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_init_chunk_t *initchunk;
__u32 init_tag;
sctp_chunk_t *err_chunk;
sctp_packet_t *packet;
sctp_disposition_t ret;
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks.
*/
if (!chunk->singleton)
return SCTP_DISPOSITION_VIOLATION;
/* Grab the INIT header. */
chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
init_tag = ntohl(chunk->subh.init_hdr->init_tag);
/* Verification Tag: 3.3.3
* If the value of the Initiate Tag in a received INIT ACK
* chunk is found to be 0, the receiver MUST treat it as an
* error and close the association by transmitting an ABORT.
*/
if (!init_tag) {
sctp_chunk_t *reply = sctp_make_abort(asoc, chunk, 0);
if (!reply)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
}
/* Verify the INIT chunk before processing it. */
err_chunk = NULL;
if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
(sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
&err_chunk)) {
/* This chunk contains fatal error. It is to be discarded.
* Send an ABORT, with causes if there is any.
*/
if (err_chunk) {
packet = sctp_abort_pkt_new(ep, asoc, arg,
(__u8 *)(err_chunk->chunk_hdr) +
sizeof(sctp_chunkhdr_t),
ntohs(err_chunk->chunk_hdr->length) -
sizeof(sctp_chunkhdr_t));
sctp_free_chunk(err_chunk);
if (packet) {
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
SCTP_PACKET(packet));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB,
SCTP_NULL());
return SCTP_DISPOSITION_CONSUME;
} else {
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB,
SCTP_NULL());
return SCTP_DISPOSITION_NOMEM;
}
} else {
ret = sctp_sf_tabort_8_4_8(ep, asoc, type, arg,
commands);
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB,
SCTP_NULL());
return ret;
}
}
/* Tag the variable length paramters. Note that we never
* convert the parameters in an INIT chunk.
*/
chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t));
initchunk = (sctp_init_chunk_t *) chunk->chunk_hdr;
sctp_add_cmd_sf(commands, SCTP_CMD_PEER_INIT,
SCTP_PEER_INIT(initchunk));
/* 5.1 C) "A" shall stop the T1-init timer and leave
* COOKIE-WAIT state. "A" shall then ... start the T1-cookie
* timer, and enter the COOKIE-ECHOED state.
*/
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,
SCTP_STATE(SCTP_STATE_COOKIE_ECHOED));
/* 5.1 C) "A" shall then send the State Cookie received in the
* INIT ACK chunk in a COOKIE ECHO chunk, ...
*/
/* If there is any errors to report, send the ERROR chunk generated
* for unknown parameters as well.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_GEN_COOKIE_ECHO,
SCTP_CHUNK(err_chunk));
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* Respond to a normal COOKIE ECHO chunk.
* We are the side that is being asked for an association.
*
* Section: 5.1 Normal Establishment of an Association, D
* D) Upon reception of the COOKIE ECHO chunk, Endpoint "Z" will reply
* with a COOKIE ACK chunk after building a TCB and moving to
* the ESTABLISHED state. A COOKIE ACK chunk may be bundled with
* any pending DATA chunks (and/or SACK chunks), but the COOKIE ACK
* chunk MUST be the first chunk in the packet.
*
* IMPLEMENTATION NOTE: An implementation may choose to send the
* Communication Up notification to the SCTP user upon reception
* of a valid COOKIE ECHO chunk.
*
* Verification Tag: 8.5.1 Exceptions in Verification Tag Rules
* D) Rules for packet carrying a COOKIE ECHO
*
* - When sending a COOKIE ECHO, the endpoint MUST use the value of the
* Initial Tag received in the INIT ACK.
*
* - The receiver of a COOKIE ECHO follows the procedures in Section 5.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type, void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_association_t *new_asoc;
sctp_init_chunk_t *peer_init;
sctp_chunk_t *repl;
sctp_ulpevent_t *ev;
int error = 0;
sctp_chunk_t *err_chk_p;
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond with an ABORT.
*/
if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
return sctp_sf_ootb(ep, asoc, type, arg, commands);
/* "Decode" the chunk. We have no optional parameters so we
* are in good shape.
*/
chunk->subh.cookie_hdr =
(sctp_signed_cookie_t *)chunk->skb->data;
skb_pull(chunk->skb,
ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t));
/* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint
* "Z" will reply with a COOKIE ACK chunk after building a TCB
* and moving to the ESTABLISHED state.
*/
new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error,
&err_chk_p);
/* FIXME:
* If the re-build failed, what is the proper error path
* from here?
*
* [We should abort the association. --piggy]
*/
if (!new_asoc) {
/* FIXME: Several errors are possible. A bad cookie should
* be silently discarded, but think about logging it too.
*/
switch (error) {
case -SCTP_IERROR_NOMEM:
goto nomem;
case -SCTP_IERROR_STALE_COOKIE:
sctp_send_stale_cookie_err(ep, asoc, chunk, commands,
err_chk_p);
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
case -SCTP_IERROR_BAD_SIG:
default:
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
};
}
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_ESTABLISHED));
sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
if (new_asoc->autoclose)
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
/* Re-build the bind address for the association is done in
* the sctp_unpack_cookie() already.
*/
/* This is a brand-new association, so these are not yet side
* effects--it is safe to run them here.
*/
peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
&chunk->subh.cookie_hdr->c.peer_addr,
peer_init, GFP_ATOMIC))
goto nomem_init;
repl = sctp_make_cookie_ack(new_asoc, chunk);
if (!repl)
goto nomem_repl;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
/* RFC 2960 5.1 Normal Establishment of an Association
*
* D) IMPLEMENTATION NOTE: An implementation may choose to
* send the Communication Up notification to the SCTP user
* upon reception of a valid COOKIE ECHO chunk.
*/
ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, SCTP_COMM_UP, 0,
new_asoc->c.sinit_num_ostreams,
new_asoc->c.sinit_max_instreams,
GFP_ATOMIC);
if (!ev)
goto nomem_ev;
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
return SCTP_DISPOSITION_CONSUME;
nomem_ev:
sctp_free_chunk(repl);
nomem_repl:
nomem_init:
sctp_association_free(new_asoc);
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* Respond to a normal COOKIE ACK chunk.
* We are the side that is being asked for an association.
*
* RFC 2960 5.1 Normal Establishment of an Association
*
* E) Upon reception of the COOKIE ACK, endpoint "A" will move from the
* COOKIE-ECHOED state to the ESTABLISHED state, stopping the T1-cookie
* timer. It may also notify its ULP about the successful
* establishment of the association with a Communication Up
* notification (see Section 10).
*
* Verification Tag:
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type, void *arg,
sctp_cmd_seq_t *commands)
{
sctp_ulpevent_t *ev;
/* RFC 2960 5.1 Normal Establishment of an Association
*
* E) Upon reception of the COOKIE ACK, endpoint "A" will move
* from the COOKIE-ECHOED state to the ESTABLISHED state,
* stopping the T1-cookie timer.
*/
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,
SCTP_STATE(SCTP_STATE_ESTABLISHED));
sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
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
* notification (see Section 10).
*/
ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP,
0, asoc->c.sinit_num_ostreams,
asoc->c.sinit_max_instreams,
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 sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
struct sctp_transport *transport = (struct sctp_transport *) arg;
sctp_chunk_t *reply;
sctp_sender_hb_info_t hbinfo;
size_t paylen = 0;
hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO;
hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t));
hbinfo.daddr = transport->ipaddr;
hbinfo.sent_at = jiffies;
/* Send a heartbeat to our peer. */
paylen = sizeof(sctp_sender_hb_info_t);
reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen);
if (!reply)
return SCTP_DISPOSITION_NOMEM;
/* Set rto_pending indicating that an RTT measurement
* is started with this heartbeat chunk.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_RTO_PENDING,
SCTP_TRANSPORT(transport));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
return SCTP_DISPOSITION_CONSUME;
}
/* Generate a HEARTBEAT packet on the given transport. */
sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
struct sctp_transport *transport = (struct sctp_transport *) arg;
if (asoc->overall_error_count >= asoc->overall_error_threshold) {
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
}
/* Section 3.3.5.
* The Sender-specific Heartbeat Info field should normally include
* information about the sender's current time when this HEARTBEAT
* chunk is sent and the destination transport address to which this
* HEARTBEAT is sent (see Section 8.3).
*/
if (transport->hb_allowed) {
if (SCTP_DISPOSITION_NOMEM ==
sctp_sf_heartbeat(ep, asoc, type, arg,
commands))
return SCTP_DISPOSITION_NOMEM;
/* Set transport error counter and association error counter
* when sending heartbeat.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET,
SCTP_TRANSPORT(transport));
}
sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMER_UPDATE,
SCTP_TRANSPORT(transport));
return SCTP_DISPOSITION_CONSUME;
}
/*
* Process an heartbeat request.
*
* Section: 8.3 Path Heartbeat
* The receiver of the HEARTBEAT should immediately respond with a
* HEARTBEAT ACK that contains the Heartbeat Information field copied
* from the received HEARTBEAT chunk.
*
* Verification Tag: 8.5 Verification Tag [Normal verification]
* When receiving an SCTP packet, the endpoint MUST ensure that the
* value in the Verification Tag field of the received SCTP packet
* matches its own Tag. If the received Verification Tag value does not
* match the receiver's own tag value, the receiver shall silently
* discard the packet and shall not process it any further except for
* those cases listed in Section 8.5.1 below.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_beat_8_3(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_chunk_t *reply;
size_t paylen = 0;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. If the received
* Verification Tag value does not match the receiver's own
* tag value, the receiver shall silently discard the packet...
*/
if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag)
return sctp_sf_pdiscard(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.
*/
chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data;
paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t);
skb_pull(chunk->skb, paylen);
reply = sctp_make_heartbeat_ack(asoc, chunk,
chunk->subh.hb_hdr, paylen);
if (!reply)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* Process the returning HEARTBEAT ACK.
*
* Section: 8.3 Path Heartbeat
* Upon the receipt of the HEARTBEAT ACK, the sender of the HEARTBEAT
* should clear the error counter of the destination transport
* address to which the HEARTBEAT was sent, and mark the destination
* transport address as active if it is not so marked. The endpoint may
* optionally report to the upper layer when an inactive destination
* address is marked as active due to the reception of the latest
* HEARTBEAT ACK. The receiver of the HEARTBEAT ACK must also
* clear the association overall error count as well (as defined
* in section 8.1).
*
* The receiver of the HEARTBEAT ACK should also perform an RTT
* measurement for that destination transport address using the time
* value carried in the HEARTBEAT ACK chunk.
*
* Verification Tag: 8.5 Verification Tag [Normal verification]
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
union sctp_addr from_addr;
struct sctp_transport *link;
sctp_sender_hb_info_t *hbinfo;
unsigned long max_interval;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. ...
*/
if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag)
return sctp_sf_pdiscard(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);
/* This should never happen, but lets log it if so. */
if (!link) {
printk(KERN_WARNING
"%s: Could not find address %d.%d.%d.%d\n",
__FUNCTION__, NIPQUAD(from_addr.v4.sin_addr));
return SCTP_DISPOSITION_DISCARD;
}
max_interval = link->hb_interval + link->rto;
/* Check if the timestamp looks valid. */
if (time_after(hbinfo->sent_at, jiffies) ||
time_after(jiffies, hbinfo->sent_at + max_interval)) {
SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp"
"received for transport: %p\n",
__FUNCTION__, link);
return SCTP_DISPOSITION_DISCARD;
}
/* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of
* the HEARTBEAT should clear the error counter of the
* destination transport address to which the HEARTBEAT was
* sent and mark the destination transport address as active if
* it is not so marked.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_ON, SCTP_TRANSPORT(link));
return SCTP_DISPOSITION_CONSUME;
}
/* Helper function to send out an abort for the restart
* condition.
*/
static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
sctp_chunk_t *init,
sctp_cmd_seq_t *commands)
{
int len;
sctp_packet_t *pkt;
sctp_addr_param_t *addrparm;
sctp_errhdr_t *errhdr;
sctp_endpoint_t *ep;
char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)];
/* Build the error on the stack. We are way to malloc
* malloc crazy throughout the code today.
*/
errhdr = (sctp_errhdr_t *)buffer;
addrparm = (sctp_addr_param_t *)errhdr->variable;
/* Copy into a parm format. */
len = sockaddr2sctp_addr(ssa, addrparm);
len += sizeof(sctp_errhdr_t);
errhdr->cause = SCTP_ERROR_RESTART;
errhdr->length = htons(len);
/* Assign to the control socket. */
ep = sctp_sk((sctp_get_ctl_sock()))->ep;
/* Association is NULL since this may be a restart attack and we
* want to send back the attacker's vtag.
*/
pkt = sctp_abort_pkt_new(ep, NULL, init, errhdr, len);
if (!pkt)
goto out;
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(pkt));
/* Discard the rest of the inbound packet. */
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
out:
/* Even if there is no memory, treat as a failure so
* the packet will get dropped.
*/
return 0;
}
/* A restart is occuring, check to make sure no new addresses
* are being added as we may be under a takeover attack.
*/
static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc,
const sctp_association_t *asoc,
sctp_chunk_t *init,
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
* ...
* Before responding the endpoint MUST check to see if the
* unexpected INIT adds new addresses to the association. If new
* addresses are added to the association, the endpoint MUST respond
* with an ABORT..
*/
/* Search through all current addresses and make sure
* we aren't adding any new ones.
*/
new_addr = 0;
found = 0;
list_for_each(pos, &new_asoc->peer.transport_addr_list) {
new_addr = list_entry(pos, struct sctp_transport, transports);
found = 0;
list_for_each(pos2, &asoc->peer.transport_addr_list) {
addr = list_entry(pos2, struct sctp_transport,
transports);
if (sctp_cmp_addr_exact(&new_addr->ipaddr,
&addr->ipaddr)) {
found = 1;
break;
}
}
if (!found)
break;
}
/* If a new address was added, ABORT the sender. */
if (!found && new_addr) {
sctp_sf_send_restart_abort(&new_addr->ipaddr, init, commands);
}
/* Return success if all addresses were found. */
return found;
}
/* Populate the verification/tie tags based on overlapping INIT
* scenario.
*
* Note: Do not use in CLOSED or SHUTDOWN-ACK-SENT state.
*/
static void sctp_tietags_populate(sctp_association_t *new_asoc,
const sctp_association_t *asoc)
{
switch (asoc->state) {
/* 5.2.1 INIT received in COOKIE-WAIT or COOKIE-ECHOED State */
case SCTP_STATE_COOKIE_WAIT:
new_asoc->c.my_vtag = asoc->c.my_vtag;
new_asoc->c.my_ttag = asoc->c.my_vtag;
new_asoc->c.peer_ttag = 0;
break;
case SCTP_STATE_COOKIE_ECHOED:
new_asoc->c.my_vtag = asoc->c.my_vtag;
new_asoc->c.my_ttag = asoc->c.my_vtag;
new_asoc->c.peer_ttag = asoc->c.peer_vtag;
break;
/* 5.2.2 Unexpected INIT in States Other than CLOSED, COOKIE-ECHOED,
* COOKIE-WAIT and SHUTDOWN-ACK-SENT
*/
default:
new_asoc->c.my_ttag = asoc->c.my_vtag;
new_asoc->c.peer_ttag = asoc->c.peer_vtag;
break;
};
/* Other parameters for the endpoint SHOULD be copied from the
* existing parameters of the association (e.g. number of
* outbound streams) into the INIT ACK and cookie.
*/
new_asoc->rwnd = asoc->rwnd;
new_asoc->c.sinit_num_ostreams = asoc->c.sinit_num_ostreams;
new_asoc->c.sinit_max_instreams = asoc->c.sinit_max_instreams;
new_asoc->c.initial_tsn = asoc->c.initial_tsn;
}
/*
* Compare vtag/tietag values to determine unexpected COOKIE-ECHO
* handling action.
*
* RFC 2960 5.2.4 Handle a COOKIE ECHO when a TCB exists.
*
* Returns value representing action to be taken. These action values
* correspond to Action/Description values in RFC 2960, Table 2.
*/
static char sctp_tietags_compare(sctp_association_t *new_asoc,
const sctp_association_t *asoc)
{
/* In this case, the peer may have restarted. */
if ((asoc->c.my_vtag != new_asoc->c.my_vtag) &&
(asoc->c.peer_vtag != new_asoc->c.peer_vtag) &&
(asoc->c.my_vtag == new_asoc->c.my_ttag) &&
(asoc->c.peer_vtag == new_asoc->c.peer_ttag))
return 'A';
/* Collision case B. */
if ((asoc->c.my_vtag == new_asoc->c.my_vtag) &&
((asoc->c.peer_vtag != new_asoc->c.peer_vtag) ||
(0 == asoc->c.peer_vtag))) {
return 'B';
}
/* Collision case D. */
if ((asoc->c.my_vtag == new_asoc->c.my_vtag) &&
(asoc->c.peer_vtag == new_asoc->c.peer_vtag))
return 'D';
/* Collision case C. */
if ((asoc->c.my_vtag != new_asoc->c.my_vtag) &&
(asoc->c.peer_vtag == new_asoc->c.peer_vtag) &&
(0 == new_asoc->c.my_ttag) &&
(0 == new_asoc->c.peer_ttag))
return 'C';
/* No match to any of the special cases; discard this packet. */
return 'E';
}
/* Common helper routine for both duplicate and simulataneous INIT
* chunk handling.
*/
static sctp_disposition_t sctp_sf_do_unexpected_init(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg, sctp_cmd_seq_t *commands)
{
sctp_disposition_t retval;
sctp_chunk_t *chunk = arg;
sctp_chunk_t *repl;
sctp_association_t *new_asoc;
sctp_chunk_t *err_chunk;
sctp_packet_t *packet;
sctp_unrecognized_param_t *unk_param;
int len;
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks.
*/
if (!chunk->singleton)
return SCTP_DISPOSITION_VIOLATION;
/* Grab the INIT header. */
chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
/* Tag the variable length parameters. */
chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t));
/* Verify the INIT chunk before processing it. */
err_chunk = NULL;
if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
(sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
&err_chunk)) {
/* This chunk contains fatal error. It is to be discarded.
* Send an ABORT, with causes if there is any.
*/
if (err_chunk) {
packet = sctp_abort_pkt_new(ep, asoc, arg,
(__u8 *)(err_chunk->chunk_hdr) +
sizeof(sctp_chunkhdr_t),
ntohs(err_chunk->chunk_hdr->length) -
sizeof(sctp_chunkhdr_t));
if (packet) {
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
SCTP_PACKET(packet));
retval = SCTP_DISPOSITION_CONSUME;
} else {
retval = SCTP_DISPOSITION_NOMEM;
}
goto cleanup;
} else {
return sctp_sf_tabort_8_4_8(ep, asoc, type, arg,
commands);
}
}
/*
* Other parameters for the endpoint SHOULD be copied from the
* existing parameters of the association (e.g. number of
* outbound streams) into the INIT ACK and cookie.
* FIXME: We are copying parameters from the endpoint not the
* association.
*/
new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC);
if (!new_asoc)
goto nomem;
/* In the outbound INIT ACK the endpoint MUST copy its current
* Verification Tag and Peers Verification tag into a reserved
* place (local tie-tag and per tie-tag) within the state cookie.
*/
if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
sctp_source(chunk),
(sctp_init_chunk_t *)chunk->chunk_hdr,
GFP_ATOMIC)) {
retval = SCTP_DISPOSITION_NOMEM;
goto nomem_init;
}
/* Make sure no new addresses are being added during the
* restart. Do not do this check for COOKIE-WAIT state,
* since there are no peer addresses to check against.
* Upon return an ABORT will have been sent if needed.
*/
if (asoc->state != SCTP_STATE_COOKIE_WAIT) {
if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk,
commands)) {
retval = SCTP_DISPOSITION_CONSUME;
goto cleanup_asoc;
}
}
sctp_tietags_populate(new_asoc, asoc);
/* B) "Z" shall respond immediately with an INIT ACK chunk. */
/* If there are errors need to be reported for unknown parameters,
* make sure to reserve enough room in the INIT ACK for them.
*/
len = 0;
if (err_chunk) {
len = ntohs(err_chunk->chunk_hdr->length) -
sizeof(sctp_chunkhdr_t);
}
if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0)
goto nomem;
repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
if (!repl)
goto nomem;
/* If there are errors need to be reported for unknown parameters,
* include them in the outgoing INIT ACK as "Unrecognized parameter"
* parameter.
*/
if (err_chunk) {
/* Get the "Unrecognized parameter" parameter(s) out of the
* ERROR chunk generated by sctp_verify_init(). Since the
* error cause code for "unknown parameter" and the
* "Unrecognized parameter" type is the same, we can
* construct the parameters in INIT ACK by copying the
* ERROR causes over.
*/
unk_param = (sctp_unrecognized_param_t *)
((__u8 *)(err_chunk->chunk_hdr) +
sizeof(sctp_chunkhdr_t));
/* Replace the cause code with the "Unrecognized parameter"
* parameter type.
*/
sctp_addto_chunk(repl, len, unk_param);
sctp_free_chunk(err_chunk);
}
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
/*
* Note: After sending out INIT ACK with the State Cookie parameter,
* "Z" MUST NOT allocate any resources for this new association.
* Otherwise, "Z" will be vulnerable to resource attacks.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
retval = SCTP_DISPOSITION_CONSUME;
cleanup:
if (err_chunk)
sctp_free_chunk(err_chunk);
return retval;
nomem:
retval = SCTP_DISPOSITION_NOMEM;
goto cleanup;
nomem_init:
cleanup_asoc:
sctp_association_free(new_asoc);
goto cleanup;
}
/*
* Handle simultanous INIT.
* This means we started an INIT and then we got an INIT request from
* our peer.
*
* Section: 5.2.1 INIT received in COOKIE-WAIT or COOKIE-ECHOED State (Item B)
* This usually indicates an initialization collision, i.e., each
* endpoint is attempting, at about the same time, to establish an
* association with the other endpoint.
*
* Upon receipt of an INIT in the COOKIE-WAIT or COOKIE-ECHOED state, an
* endpoint MUST respond with an INIT ACK using the same parameters it
* sent in its original INIT chunk (including its Verification Tag,
* unchanged). These original parameters are combined with those from the
* newly received INIT chunk. The endpoint shall also generate a State
* Cookie with the INIT ACK. The endpoint uses the parameters sent in its
* INIT to calculate the State Cookie.
*
* After that, the endpoint MUST NOT change its state, the T1-init
* timer shall be left running and the corresponding TCB MUST NOT be
* destroyed. The normal procedures for handling State Cookies when
* a TCB exists will resolve the duplicate INITs to a single association.
*
* For an endpoint that is in the COOKIE-ECHOED state it MUST populate
* its Tie-Tags with the Tag information of itself and its peer (see
* section 5.2.2 for a description of the Tie-Tags).
*
* Verification Tag: Not explicit, but an INIT can not have a valid
* verification tag, so we skip the check.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* Call helper to do the real work for both simulataneous and
* duplicate INIT chunk handling.
*/
return sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands);
}
/*
* Handle duplicated INIT messages. These are usually delayed
* restransmissions.
*
* Section: 5.2.2 Unexpected INIT in States Other than CLOSED,
* COOKIE-ECHOED and COOKIE-WAIT
*
* Unless otherwise stated, upon reception of an unexpected INIT for
* this association, the endpoint shall generate an INIT ACK with a
* State Cookie. In the outbound INIT ACK the endpoint MUST copy its
* current Verification Tag and peer's Verification Tag into a reserved
* place within the state cookie. We shall refer to these locations as
* the Peer's-Tie-Tag and the Local-Tie-Tag. The outbound SCTP packet
* containing this INIT ACK MUST carry a Verification Tag value equal to
* the Initiation Tag found in the unexpected INIT. And the INIT ACK
* MUST contain a new Initiation Tag (randomly generated see Section
* 5.3.1). Other parameters for the endpoint SHOULD be copied from the
* existing parameters of the association (e.g. number of outbound
* streams) into the INIT ACK and cookie.
*
* After sending out the INIT ACK, the endpoint shall take no further
* actions, i.e., the existing association, including its current state,
* and the corresponding TCB MUST NOT be changed.
*
* Note: Only when a TCB exists and the association is not in a COOKIE-
* WAIT state are the Tie-Tags populated. For a normal association INIT
* (i.e. the endpoint is in a COOKIE-WAIT state), the Tie-Tags MUST be
* set to 0 (indicating that no previous TCB existed). The INIT ACK and
* State Cookie are populated as specified in section 5.2.1.
*
* Verification Tag: Not specifed, but an INIT has no way of knowing
* what the verification tag could be, so we ignore it.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* Call helper to do the real work for both simulataneous and
* duplicate INIT chunk handling.
*/
return sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands);
}
/* Unexpected COOKIE-ECHO handler for peer restart (Table 2, action 'A')
*
* Section 5.2.4
* A) In this case, the peer may have restarted.
*/
static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
sctp_chunk_t *chunk,
sctp_cmd_seq_t *commands,
sctp_association_t *new_asoc)
{
sctp_init_chunk_t *peer_init;
sctp_ulpevent_t *ev;
sctp_chunk_t *repl;
/* new_asoc is a brand-new association, so these are not yet
* side effects--it is safe to run them here.
*/
peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
sctp_source(chunk), peer_init, GFP_ATOMIC))
goto nomem;
/* Make sure no new addresses are being added during the
* restart. Though this is a pretty complicated attack
* since you'd have to get inside the cookie.
*/
if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) {
return SCTP_DISPOSITION_CONSUME;
}
/* For now, fail any unsent/unacked data. Consider the optional
* choice of resending of this data.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL());
/* Update the content of current association. */
sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
repl = sctp_make_cookie_ack(new_asoc, chunk);
if (!repl)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
/* Report association restart to upper layer. */
ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0,
new_asoc->c.sinit_num_ostreams,
new_asoc->c.sinit_max_instreams,
GFP_ATOMIC);
if (!ev)
goto nomem_ev;
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
return SCTP_DISPOSITION_CONSUME;
nomem_ev:
sctp_free_chunk(repl);
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/* Unexpected COOKIE-ECHO handler for setup collision (Table 2, action 'B')
*
* Section 5.2.4
* B) In this case, both sides may be attempting to start an association
* at about the same time but the peer endpoint started its INIT
* after responding to the local endpoint's INIT
*/
/* This case represents an intialization collision. */
static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
sctp_chunk_t *chunk,
sctp_cmd_seq_t *commands,
sctp_association_t *new_asoc)
{
sctp_init_chunk_t *peer_init;
sctp_ulpevent_t *ev;
sctp_chunk_t *repl;
/* new_asoc is a brand-new association, so these are not yet
* side effects--it is safe to run them here.
*/
peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
sctp_source(chunk), peer_init, GFP_ATOMIC))
goto nomem;
/* Update the content of current association. */
sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_ESTABLISHED));
sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, 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));
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
/* RFC 2960 5.1 Normal Establishment of an Association
*
* D) IMPLEMENTATION NOTE: An implementation may choose to
* send the Communication Up notification to the SCTP user
* upon reception of a valid COOKIE ECHO chunk.
*/
ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0,
new_asoc->c.sinit_num_ostreams,
new_asoc->c.sinit_max_instreams,
GFP_ATOMIC);
if (!ev)
goto nomem_ev;
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
return SCTP_DISPOSITION_CONSUME;
nomem_ev:
sctp_free_chunk(repl);
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/* Unexpected COOKIE-ECHO handler for setup collision (Table 2, action 'C')
*
* Section 5.2.4
* C) In this case, the local endpoint's cookie has arrived late.
* Before it arrived, the local endpoint sent an INIT and received an
* INIT-ACK and finally sent a COOKIE ECHO with the peer's same tag
* but a new tag of its own.
*/
/* This case represents an intialization collision. */
static sctp_disposition_t sctp_sf_do_dupcook_c(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
sctp_chunk_t *chunk,
sctp_cmd_seq_t *commands,
sctp_association_t *new_asoc)
{
/* The cookie should be silently discarded.
* The endpoint SHOULD NOT change states and should leave
* any timers running.
*/
return SCTP_DISPOSITION_DISCARD;
}
/* Unexpected COOKIE-ECHO handler lost chunk (Table 2, action 'D')
*
* Section 5.2.4
*
* D) When both local and remote tags match the endpoint should always
* enter the ESTABLISHED state, if it has not already done so.
*/
/* This case represents an intialization collision. */
static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
sctp_chunk_t *chunk,
sctp_cmd_seq_t *commands,
sctp_association_t *new_asoc)
{
sctp_ulpevent_t *ev = NULL;
sctp_chunk_t *repl;
/* Clarification from Implementor's Guide:
* D) When both local and remote tags match the endpoint should
* enter the ESTABLISHED state, if it is in the COOKIE-ECHOED state.
* It should stop any cookie timer that may be running and send
* a COOKIE ACK.
*/
/* Don't accidentally move back into established state. */
if (asoc->state < SCTP_STATE_ESTABLISHED) {
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,
SCTP_STATE(SCTP_STATE_ESTABLISHED));
sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START,
SCTP_NULL());
/* RFC 2960 5.1 Normal Establishment of an Association
*
* D) IMPLEMENTATION NOTE: An implementation may choose
* to send the Communication Up notification to the
* SCTP user upon reception of a valid COOKIE
* ECHO chunk.
*/
ev = sctp_ulpevent_make_assoc_change(new_asoc, 0,
SCTP_COMM_UP, 0,
new_asoc->c.sinit_num_ostreams,
new_asoc->c.sinit_max_instreams,
GFP_ATOMIC);
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());
repl = sctp_make_cookie_ack(new_asoc, chunk);
if (!repl)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
return SCTP_DISPOSITION_CONSUME;
nomem:
if (ev)
sctp_ulpevent_free(ev);
return SCTP_DISPOSITION_NOMEM;
}
/*
* Handle a duplicate COOKIE-ECHO. This usually means a cookie-carrying
* chunk was retransmitted and then delayed in the network.
*
* Section: 5.2.4 Handle a COOKIE ECHO when a TCB exists
*
* Verification Tag: None. Do cookie validation.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_disposition_t retval;
sctp_chunk_t *chunk = arg;
sctp_association_t *new_asoc;
int error = 0;
char action;
sctp_chunk_t *err_chk_p;
/* "Decode" the chunk. We have no optional parameters so we
* are in good shape.
*/
chunk->subh.cookie_hdr = (sctp_signed_cookie_t *)chunk->skb->data;
skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
sizeof(sctp_chunkhdr_t));
/* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie
* of a duplicate COOKIE ECHO match the Verification Tags of the
* current association, consider the State Cookie valid even if
* the lifespan is exceeded.
*/
new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error,
&err_chk_p);
/* FIXME:
* If the re-build failed, what is the proper error path
* from here?
*
* [We should abort the association. --piggy]
*/
if (!new_asoc) {
/* FIXME: Several errors are possible. A bad cookie should
* be silently discarded, but think about logging it too.
*/
switch (error) {
case -SCTP_IERROR_NOMEM:
goto nomem;
case -SCTP_IERROR_STALE_COOKIE:
sctp_send_stale_cookie_err(ep, asoc, chunk, commands,
err_chk_p);
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
case -SCTP_IERROR_BAD_SIG:
default:
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
};
}
/* Compare the tie_tag in cookie with the verification tag of
* current association.
*/
action = sctp_tietags_compare(new_asoc, asoc);
switch (action) {
case 'A': /* Association restart. */
retval = sctp_sf_do_dupcook_a(ep, asoc, chunk, commands,
new_asoc);
break;
case 'B': /* Collision case B. */
retval = sctp_sf_do_dupcook_b(ep, asoc, chunk, commands,
new_asoc);
break;
case 'C': /* Collision case C. */
retval = sctp_sf_do_dupcook_c(ep, asoc, chunk, commands,
new_asoc);
break;
case 'D': /* Collision case D. */
retval = sctp_sf_do_dupcook_d(ep, asoc, chunk, commands,
new_asoc);
break;
default: /* Discard packet for all others. */
retval = sctp_sf_pdiscard(ep, asoc, type, arg, commands);
break;
};
/* Delete the tempory new association. */
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
return retval;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* Process an ABORT. (SHUTDOWN-PENDING state)
*
* See sctp_sf_do_9_1_abort().
*/
sctp_disposition_t sctp_sf_shutdown_pending_abort(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
if (!sctp_vtag_verify_either(chunk, asoc))
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));
return sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
}
/*
* Process an ABORT. (SHUTDOWN-SENT state)
*
* See sctp_sf_do_9_1_abort().
*/
sctp_disposition_t sctp_sf_shutdown_sent_abort(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
if (!sctp_vtag_verify_either(chunk, asoc))
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));
/* Stop the T5-shutdown guard timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
return sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
}
/*
* Process an ABORT. (SHUTDOWN-ACK-SENT state)
*
* See sctp_sf_do_9_1_abort().
*/
sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* The same T2 timer, so we should be able to use
* common function with the SHUTDOWN-SENT state.
*/
return sctp_sf_shutdown_sent_abort(ep, asoc, type, arg, commands);
}
/*
* Handle an Error received in COOKIE_ECHOED state.
*
* Only handle the error type of stale COOKIE Error, the other errors will
* be ignored.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_errhdr_t *err;
/* If we have gotten too many failures, give up. */
if (1 + asoc->counters[SCTP_COUNTER_INIT_ERROR] >
asoc->max_init_attempts) {
/* INIT_FAILED will issue an ulpevent. */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
}
err = (sctp_errhdr_t *)(chunk->skb->data);
/* Process the error here */
switch (err->cause) {
case SCTP_ERROR_STALE_COOKIE:
return sctp_sf_do_5_2_6_stale(ep, asoc, type, arg, commands);
default:
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
}
}
/*
* Handle a Stale COOKIE Error
*
* Section: 5.2.6 Handle Stale COOKIE Error
* If the association is in the COOKIE-ECHOED state, the endpoint may elect
* one of the following three alternatives.
* ...
* 3) Send a new INIT chunk to the endpoint, adding a Cookie
* Preservative parameter requesting an extension to the lifetime of
* the State Cookie. When calculating the time extension, an
* implementation SHOULD use the RTT information measured based on the
* previous COOKIE ECHO / ERROR exchange, and should add no more
* than 1 second beyond the measured RTT, due to long State Cookie
* lifetimes making the endpoint more subject to a replay attack.
*
* Verification Tag: Not explicit, but safe to ignore.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
time_t stale;
sctp_cookie_preserve_param_t bht;
sctp_errhdr_t *err;
struct list_head *pos;
struct sctp_transport *t;
sctp_chunk_t *reply;
sctp_bind_addr_t *bp;
int attempts;
attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1;
if (attempts >= asoc->max_init_attempts) {
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
}
err = (sctp_errhdr_t *)(chunk->skb->data);
/* When calculating the time extension, an implementation
* SHOULD use the RTT information measured based on the
* previous COOKIE ECHO / ERROR exchange, and should add no
* more than 1 second beyond the measured RTT, due to long
* State Cookie lifetimes making the endpoint more subject to
* a replay attack.
* Measure of Staleness's unit is usec. (1/1000000 sec)
* Suggested Cookie Life-span Increment's unit is msec.
* (1/1000 sec)
* In general, if you use the suggested cookie life, the value
* found in the field of measure of staleness should be doubled
* to give ample time to retransmit the new cookie and thus
* yield a higher probability of success on the reattempt.
*/
stale = ntohl(*(suseconds_t *)((u8 *)err + sizeof(sctp_errhdr_t)));
stale = stale << 1 / 1000;
bht.param_hdr.type = SCTP_PARAM_COOKIE_PRESERVATIVE;
bht.param_hdr.length = htons(sizeof(bht));
bht.lifespan_increment = htonl(stale);
/* Build that new INIT chunk. */
bp = (sctp_bind_addr_t *) &asoc->base.bind_addr;
reply = sctp_make_init(asoc, bp, GFP_ATOMIC, sizeof(bht));
if (!reply)
goto nomem;
sctp_addto_chunk(reply, sizeof(bht), &bht);
/* 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,
SCTP_STATE(SCTP_STATE_COOKIE_WAIT));
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* Process an ABORT.
*
* Section: 9.1
* After checking the Verification Tag, the receiving endpoint shall
* remove the association from its record, and shall report the
* termination to its upper layer.
*
* Verification Tag: 8.5.1 Exceptions in Verification Tag Rules
* B) Rules for packet carrying ABORT:
*
* - The endpoint shall always fill in the Verification Tag field of the
* outbound packet with the destination endpoint's tag value if it
* is known.
*
* - If the ABORT is sent in response to an OOTB packet, the endpoint
* MUST follow the procedure described in Section 8.4.
*
* - The receiver MUST accept the packet if the Verification Tag
* matches either its own tag, OR the tag of its peer. Otherwise, the
* receiver MUST silently discard the packet and take no further
* action.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* ASSOC_FAILED will DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
/* BUG? This does not look complete... */
return SCTP_DISPOSITION_ABORT;
}
/*
* Process an ABORT. (COOKIE-WAIT state)
*
* See sctp_sf_do_9_1_abort() above.
*/
sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
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_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_NULL());
/* BUG? This does not look complete... */
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 sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* There is a single T1 timer, so we should be able to use
* common function with the COOKIE-WAIT state.
*/
return sctp_sf_cookie_wait_abort(ep, asoc, type, arg, commands);
}
/*
* sctp_sf_do_9_2_shut
*
* Section: 9.2
* Upon the reception of the SHUTDOWN, the peer endpoint shall
* - enter the SHUTDOWN-RECEIVED state,
*
* - stop accepting new data from its SCTP user
*
* - verify, by checking the Cumulative TSN Ack field of the chunk,
* that all its outstanding DATA chunks have been received by the
* SHUTDOWN sender.
*
* Once an endpoint as reached the SHUTDOWN-RECEIVED state it MUST NOT
* send a SHUTDOWN in response to a ULP request. And should discard
* subsequent SHUTDOWN chunks.
*
* If there are still outstanding DATA chunks left, the SHUTDOWN
* receiver shall continue to follow normal data transmission
* procedures defined in Section 6 until all outstanding DATA chunks
* are acknowledged; however, the SHUTDOWN receiver MUST NOT accept
* new data from its SCTP user.
*
* Verification Tag: 8.5 Verification Tag [Normal verification]
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_shutdownhdr_t *sdh;
sctp_disposition_t disposition;
/* Convert the elaborate header. */
sdh = (sctp_shutdownhdr_t *)chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t));
chunk->subh.shutdown_hdr = sdh;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. If the received
* Verification Tag value does not match the receiver's own
* tag value, the receiver shall silently discard the packet...
*/
if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag)
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
*
* [This is implicit in the new state.]
*/
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_SHUTDOWN_RECEIVED));
disposition = SCTP_DISPOSITION_CONSUME;
if (sctp_outq_is_empty(&asoc->outqueue)) {
disposition = sctp_sf_do_9_2_shutdown_ack(ep, asoc, type,
arg, commands);
}
/* - verify, by checking the Cumulative TSN Ack field of the
* chunk, that all its outstanding DATA chunks have been
* received by the SHUTDOWN sender.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_CTSN,
SCTP_U32(chunk->subh.shutdown_hdr->cum_tsn_ack));
return disposition;
}
/* RFC 2960 9.2
* If an endpoint is in SHUTDOWN-ACK-SENT state and receives an INIT chunk
* (e.g., if the SHUTDOWN COMPLETE was lost) with source and destination
* transport addresses (either in the IP addresses or in the INIT chunk)
* that belong to this association, it should discard the INIT chunk and
* retransmit the SHUTDOWN ACK chunk.
*/
sctp_disposition_t sctp_sf_do_9_2_reshutack(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = (sctp_chunk_t *) arg;
sctp_chunk_t *reply;
reply = sctp_make_shutdown_ack(asoc, chunk);
if (NULL == reply)
goto nomem;
/* Set the transport for the SHUTDOWN ACK chunk and the timeout for
* the T2-SHUTDOWN timer.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply));
/* and restart the T2-shutdown timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* sctp_sf_do_ecn_cwr
*
* Section: Appendix A: Explicit Congestion Notification
*
* CWR:
*
* RFC 2481 details a specific bit for a sender to send in the header of
* its next outbound TCP segment to indicate to its peer that it has
* reduced its congestion window. This is termed the CWR bit. For
* SCTP the same indication is made by including the CWR chunk.
* This chunk contains one data element, i.e. the TSN number that
* was sent in the ECNE chunk. This element represents the lowest
* TSN number in the datagram that was originally marked with the
* CE bit.
*
* Verification Tag: 8.5 Verification Tag [Normal verification]
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_cwrhdr_t *cwr;
sctp_chunk_t *chunk = arg;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. If the received
* Verification Tag value does not match the receiver's own
* tag value, the receiver shall silently discard the packet...
*/
if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
cwr = (sctp_cwrhdr_t *) chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_cwrhdr_t));
cwr->lowest_tsn = ntohl(cwr->lowest_tsn);
/* Does this CWR ack the last sent congestion notification? */
if (TSN_lte(asoc->last_ecne_tsn, cwr->lowest_tsn)) {
/* Stop sending ECNE. */
sctp_add_cmd_sf(commands,
SCTP_CMD_ECN_CWR,
SCTP_U32(cwr->lowest_tsn));
}
return SCTP_DISPOSITION_CONSUME;
}
/*
* sctp_sf_do_ecne
*
* Section: Appendix A: Explicit Congestion Notification
*
* ECN-Echo
*
* RFC 2481 details a specific bit for a receiver to send back in its
* TCP acknowledgements to notify the sender of the Congestion
* Experienced (CE) bit having arrived from the network. For SCTP this
* same indication is made by including the ECNE chunk. This chunk
* contains one data element, i.e. the lowest TSN associated with the IP
* datagram marked with the CE bit.....
*
* Verification Tag: 8.5 Verification Tag [Normal verification]
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_ecnehdr_t *ecne;
sctp_chunk_t *chunk = arg;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. If the received
* Verification Tag value does not match the receiver's own
* tag value, the receiver shall silently discard the packet...
*/
if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
ecne = (sctp_ecnehdr_t *) chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_ecnehdr_t));
/* If this is a newer ECNE than the last CWR packet we sent out */
sctp_add_cmd_sf(commands, SCTP_CMD_ECN_ECNE,
SCTP_U32(ntohl(ecne->lowest_tsn)));
return SCTP_DISPOSITION_CONSUME;
}
/*
* Section: 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.
*
* A SCTP receiver MUST NOT generate more than one SACK for every
* incoming packet, other than to update the offered window as the
* receiving application consumes new data.
*
* Verification Tag: 8.5 Verification Tag [Normal verification]
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_datahdr_t *data_hdr;
sctp_chunk_t *err;
size_t datalen;
int tmp;
__u32 tsn;
/* RFC 2960 8.5 Verification Tag
*
* When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag.
*/
if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) {
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
SCTP_NULL());
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);
SCTP_DEBUG_PRINTK("eat_data: skb->head %p.\n", chunk->skb->head);
/* 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) {
chunk->ecn_ce_done = 1;
if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) &&
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;
}
/* 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);
if (asoc->rwnd_over || (datalen > asoc->rwnd + asoc->frag_point)) {
SCTP_DEBUG_PRINTK("Discarding tsn: %u datalen: %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_NULL());
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));
/* 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, SCTP_CMD_CHUNK_ULP, 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;
}
/*
* sctp_sf_eat_data_fast_4_4
*
* Section: 4 (4)
* (4) In SHUTDOWN-SENT state the endpoint MUST acknowledge any received
* DATA chunks without delay.
*
* Verification Tag: 8.5 Verification Tag [Normal verification]
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_datahdr_t *data_hdr;
sctp_chunk_t *err;
size_t datalen;
int tmp;
__u32 tsn;
/* RFC 2960 8.5 Verification Tag
*
* When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag.
*/
if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) {
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
SCTP_NULL());
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) {
chunk->ecn_ce_done = 1;
if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) &&
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_NULL());
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));
/* 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));
}
}
/* 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
* respond to each received packet containing one or more DATA chunk(s)
* with a SACK, a SHUTDOWN chunk, and restart the T2-shutdown timer
*/
if (chunk->end_of_packet) {
/* We must delay the chunk creation since the cumulative
* TSN has not been updated yet.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SHUTDOWN, SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE());
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
}
return SCTP_DISPOSITION_CONSUME;
}
/*
* Section: 6.2 Processing a Received SACK
* D) Any time a SACK arrives, the endpoint performs the following:
*
* i) If Cumulative TSN Ack is less than the Cumulative TSN Ack Point,
* then drop the SACK. Since Cumulative TSN Ack is monotonically
* increasing, a SACK whose Cumulative TSN Ack is less than the
* Cumulative TSN Ack Point indicates an out-of-order SACK.
*
* ii) Set rwnd equal to the newly received a_rwnd minus the number
* of bytes still outstanding after processing the Cumulative TSN Ack
* and the Gap Ack Blocks.
*
* iii) If the SACK is missing a TSN that was previously
* acknowledged via a Gap Ack Block (e.g., the data receiver
* reneged on the data), then mark the corresponding DATA chunk
* as available for retransmit: Mark it as missing for fast
* retransmit as described in Section 7.2.4 and if no retransmit
* timer is running for the destination address to which the DATA
* chunk was originally transmitted, then T3-rtx is started for
* that destination address.
*
* Verification Tag: 8.5 Verification Tag [Normal verification]
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_sackhdr_t *sackh;
__u32 ctsn;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. ...
*/
if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Pull the SACK chunk from the data buffer */
sackh = sctp_sm_pull_sack(chunk);
chunk->subh.sack_hdr = sackh;
ctsn = ntohl(sackh->cum_tsn_ack);
/* i) If Cumulative TSN Ack is less than the Cumulative TSN
* Ack Point, then drop the SACK. Since Cumulative TSN
* Ack is monotonically increasing, a SACK whose
* Cumulative TSN Ack is less than the Cumulative TSN Ack
* Point indicates an out-of-order SACK.
*/
if (TSN_lt(ctsn, asoc->ctsn_ack_point)) {
SCTP_DEBUG_PRINTK("ctsn %x\n", ctsn);
SCTP_DEBUG_PRINTK("ctsn_ack_point %x\n", asoc->ctsn_ack_point);
return SCTP_DISPOSITION_DISCARD;
}
/* Return this SACK for further processing. */
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, SCTP_SACKH(sackh));
/* Note: We do the rest of the work on the PROCESS_SACK
* sideeffect.
*/
return SCTP_DISPOSITION_CONSUME;
}
/*
* Generate an ABORT in response to a packet.
*
* Section: 8.4 Handle "Out of the blue" Packets
*
* 8) The receiver should respond to the sender of the OOTB packet
* with an ABORT. When sending the ABORT, the receiver of the
* OOTB packet MUST fill in the Verification Tag field of the
* outbound packet with the value found in the Verification Tag
* field of the OOTB packet and set the T-bit in the Chunk Flags
* to indicate that no TCB was found. After sending this ABORT,
* the receiver of the OOTB packet shall discard the OOTB packet
* and take no further action.
*
* Verification Tag:
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_packet_t *packet = NULL;
sctp_chunk_t *chunk = arg;
sctp_chunk_t *abort;
packet = sctp_ootb_pkt_new(asoc, chunk);
if (packet) {
/* Make an ABORT. The T bit will be set if the asoc
* is NULL.
*/
abort = sctp_make_abort(asoc, chunk, 0);
if (!abort) {
sctp_ootb_pkt_free(packet);
return SCTP_DISPOSITION_NOMEM;
}
/* Set the skb to the belonging sock for accounting. */
abort->skb->sk = ep->base.sk;
sctp_packet_append_chunk(packet, abort);
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
SCTP_PACKET(packet));
return SCTP_DISPOSITION_CONSUME;
}
return SCTP_DISPOSITION_NOMEM;
}
/*
* Received an ERROR chunk from peer. Generate SCTP_REMOTE_ERROR
* event as ULP notification for each cause included in the chunk.
*
* API 5.3.1.3 - SCTP_REMOTE_ERROR
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_ulpevent_t *ev;
while (chunk->chunk_end > chunk->skb->data) {
ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
GFP_ATOMIC);
if (!ev)
goto nomem;
if (!sctp_add_cmd(commands, SCTP_CMD_EVENT_ULP,
SCTP_ULPEVENT(ev))) {
sctp_ulpevent_free(ev);
goto nomem;
}
}
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* Process an inbound SHUTDOWN ACK.
*
* From Section 9.2:
* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall
* stop the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its
* peer, and remove all record of the association.
*
* The return value is the disposition.
*/
sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_chunk_t *reply;
sctp_ulpevent_t *ev;
/* 10.2 H) SHUTDOWN COMPLETE notification
*
* When SCTP completes the shutdown procedures (section 9.2) this
* notification is passed to the upper layer.
*/
ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP,
0, 0, 0, GFP_ATOMIC);
if (!ev)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
/* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall
* stop the T2-shutdown timer,
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
/* ...send a SHUTDOWN COMPLETE chunk to its peer, */
reply = sctp_make_shutdown_complete(asoc, chunk);
if (!reply)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
/* ...and remove all record of the association. */
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* RFC 2960, 8.4 - Handle "Out of the blue" Packets
* 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should
* respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE.
* When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
* packet must fill in the Verification Tag field of the outbound
* packet with the Verification Tag received in the SHUTDOWN ACK and
* set the T-bit in the Chunk Flags to indicate that no TCB was
* found. Otherwise,
*
* 8) The receiver should respond to the sender of the OOTB packet with
* an ABORT. When sending the ABORT, the receiver of the OOTB packet
* MUST fill in the Verification Tag field of the outbound packet
* with the value found in the Verification Tag field of the OOTB
* packet and set the T-bit in the Chunk Flags to indicate that no
* TCB was found. After sending this ABORT, the receiver of the OOTB
* packet shall discard the OOTB packet and take no further action.
*/
sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
struct sk_buff *skb = chunk->skb;
sctp_chunkhdr_t *ch;
__u8 *ch_end;
int ootb_shut_ack = 0;
ch = (sctp_chunkhdr_t *) chunk->chunk_hdr;
do {
ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
if (SCTP_CID_SHUTDOWN_ACK == ch->type)
ootb_shut_ack = 1;
ch = (sctp_chunkhdr_t *) ch_end;
} while (ch_end < skb->tail);
if (ootb_shut_ack)
sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands);
else
sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
}
/*
* Handle an "Out of the blue" SHUTDOWN ACK.
*
* Section: 8.4 5)
* 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should
* respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE.
* When sending the SHUTDOWN COMPLETE, the receiver of the OOTB packet
* must fill in the Verification Tag field of the outbound packet with
* the Verification Tag received in the SHUTDOWN ACK and set the
* T-bit in the Chunk Flags to indicate that no TCB was found.
*
* Inputs
* (endpoint, asoc, type, arg, commands)
*
* Outputs
* (sctp_disposition_t)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_packet_t *packet = NULL;
sctp_chunk_t *chunk = arg;
sctp_chunk_t *shut;
packet = sctp_ootb_pkt_new(asoc, chunk);
if (packet) {
/* Make an SHUTDOWN_COMPLETE.
* The T bit will be set if the asoc is NULL.
*/
shut = sctp_make_shutdown_complete(asoc, chunk);
if (!shut) {
sctp_ootb_pkt_free(packet);
return SCTP_DISPOSITION_NOMEM;
}
/* Set the skb to the belonging sock for accounting. */
shut->skb->sk = ep->base.sk;
sctp_packet_append_chunk(packet, shut);
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
SCTP_PACKET(packet));
return SCTP_DISPOSITION_CONSUME;
}
return SCTP_DISPOSITION_NOMEM;
}
/*
* Handle SHUTDOWN ACK in COOKIE_ECHOED or COOKIE_WAIT state.
*
* Verification Tag: 8.5.1 E) Rules for packet carrying a SHUTDOWN ACK
* If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state the
* procedures in section 8.4 SHOULD be followed, in other words it
* should be treated as an Out Of The Blue packet.
* [This means that we do NOT check the Verification Tag on these
* chunks. --piggy ]
*
*/
sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* Although we do have an association in this case, it corresponds
* to a restarted association. So the packet is treated as an OOTB
* packet and the state function that handles OOTB SHUTDOWN_ACK is
* called with a NULL association.
*/
return sctp_sf_shut_8_4_5(ep, NULL, type, arg, commands);
}
/*
* Process an unknown chunk.
*
* Section: 3.2. Also, 2.1 in the implementor's guide.
*
* Chunk Types are encoded such that the highest-order two bits specify
* the action that must be taken if the processing endpoint does not
* recognize the Chunk Type.
*
* 00 - Stop processing this SCTP packet and discard it, do not process
* any further chunks within it.
*
* 01 - Stop processing this SCTP packet and discard it, do not process
* any further chunks within it, and report the unrecognized
* chunk in an 'Unrecognized Chunk Type'.
*
* 10 - Skip this chunk and continue processing.
*
* 11 - Skip this chunk and continue processing, but report in an ERROR
* Chunk using the 'Unrecognized Chunk Type' cause of error.
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_unk_chunk(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *unk_chunk = arg;
sctp_chunk_t *err_chunk;
sctp_chunkhdr_t *hdr;
SCTP_DEBUG_PRINTK("Processing the unknown chunk id %d.\n", type.chunk);
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. If the received
* Verification Tag value does not match the receiver's own
* tag value, the receiver shall silently discard the packet.
*/
if (ntohl(unk_chunk->sctp_hdr->vtag) != asoc->c.my_vtag)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
switch (type.chunk & SCTP_CID_ACTION_MASK) {
case SCTP_CID_ACTION_DISCARD:
/* Discard the packet. */
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,
SCTP_ERROR_UNKNOWN_CHUNK, hdr,
WORD_ROUND(ntohs(hdr->length)));
if (err_chunk) {
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(err_chunk));
}
return SCTP_DISPOSITION_CONSUME;
break;
case SCTP_CID_ACTION_SKIP:
/* Skip the chunk. */
return SCTP_DISPOSITION_DISCARD;
break;
case SCTP_CID_ACTION_SKIP_ERR:
/* Generate an ERROR chunk as response. */
hdr = unk_chunk->chunk_hdr;
err_chunk = sctp_make_op_error(asoc, unk_chunk,
SCTP_ERROR_UNKNOWN_CHUNK, hdr,
WORD_ROUND(ntohs(hdr->length)));
if (err_chunk) {
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(err_chunk));
}
/* Skip the chunk. */
return SCTP_DISPOSITION_CONSUME;
break;
default:
break;
}
return SCTP_DISPOSITION_DISCARD;
}
/*
* Discard the chunk.
*
* Section: 0.2, 5.2.3, 5.2.5, 5.2.6, 6.0, 8.4.6, 8.5.1c, 9.2
* [Too numerous to mention...]
* Verification Tag: No verification needed.
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk);
return SCTP_DISPOSITION_DISCARD;
}
/*
* Discard the whole packet.
*
* Section: 8.4 2)
*
* 2) If the OOTB packet contains an ABORT chunk, the receiver MUST
* silently discard the OOTB packet and take no further action.
* Otherwise,
*
* Verification Tag: No verification necessary
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_pdiscard(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
return SCTP_DISPOSITION_CONSUME;
}
#if 0
/*
* We did something stupid but got lucky. Namely, we sent a HEARTBEAT
* before the association was all the way up and we did NOT get an
* ABORT.
*
* Log the fact and then process normally.
*
* Section: Not specified
* Verification Tag: 8.5 Verification Tag [Normal verification]
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t lucky(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. ...
*/
if (chunk->sctp_hdr->vtag != asoc->c.my_vtag)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
#endif /* 0 */
#if 0
/*
* The other end is doing something very stupid. We'll ignore them
* after logging their idiocy. :-)
*
* Section: Not specified
* Verification Tag: 8.5 Verification Tag [Normal verification]
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t other_stupid(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. ...
*/
if (chunk->sctp_hdr->vtag != asoc->c.my_vtag)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
#endif /* 0 */
/*
* The other end is violating protocol.
*
* Section: Not specified
* Verification Tag: Not specified
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* We simply tag the chunk as a violation. The state machine will log
* the violation and continue.
*/
sctp_disposition_t sctp_sf_violation(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
return SCTP_DISPOSITION_VIOLATION;
}
/***************************************************************************
* These are the state functions for handling primitive (Section 10) events.
***************************************************************************/
/*
* sctp_sf_do_prm_asoc
*
* Section: 10.1 ULP-to-SCTP
* B) Associate
*
* Format: ASSOCIATE(local SCTP instance name, destination transport addr,
* outbound stream count)
* -> association id [,destination transport addr list] [,outbound stream
* count]
*
* This primitive allows the upper layer to initiate an association to a
* specific peer endpoint.
*
* The peer endpoint shall be specified by one of the transport addresses
* which defines the endpoint (see Section 1.4). If the local SCTP
* instance has not been initialized, the ASSOCIATE is considered an
* error.
* [This is not relevant for the kernel implementation since we do all
* initialization at boot time. It we hadn't initialized we wouldn't
* get anywhere near this code.]
*
* An association id, which is a local handle to the SCTP association,
* will be returned on successful establishment of the association. If
* SCTP is not able to open an SCTP association with the peer endpoint,
* an error is returned.
* [In the kernel implementation, the sctp_association_t needs to
* be created BEFORE causing this primitive to run.]
*
* Other association parameters may be returned, including the
* complete destination transport addresses of the peer as well as the
* outbound stream count of the local endpoint. One of the transport
* address from the returned destination addresses will be selected by
* the local endpoint as default primary path for sending SCTP packets
* to this peer. The returned "destination transport addr list" can
* be used by the ULP to change the default primary path or to force
* sending a packet to a specific transport address. [All of this
* stuff happens when the INIT ACK arrives. This is a NON-BLOCKING
* function.]
*
* Mandatory attributes:
*
* o local SCTP instance name - obtained from the INITIALIZE operation.
* [This is the argument asoc.]
* o destination transport addr - specified as one of the transport
* addresses of the peer endpoint with which the association is to be
* established.
* [This is asoc->peer.active_path.]
* o outbound stream count - the number of outbound streams the ULP
* would like to open towards this peer endpoint.
* [BUG: This is not currently implemented.]
* Optional attributes:
*
* None.
*
* The return value is a disposition.
*/
sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *repl;
/* The comment below says that we enter COOKIE-WAIT AFTER
* sending the INIT, but that doesn't actually work in our
* implementation...
*/
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_COOKIE_WAIT));
/* RFC 2960 5.1 Normal Establishment of an Association
*
* A) "A" first sends an INIT chunk to "Z". In the INIT, "A"
* must provide its Verification Tag (Tag_A) in the Initiate
* Tag field. Tag_A SHOULD be a random number in the range of
* 1 to 4294967295 (see 5.3.1 for Tag value selection). ...
*/
repl = sctp_make_init(asoc, &asoc->base.bind_addr, GFP_ATOMIC, 0);
if (!repl)
goto nomem;
/* 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((sctp_association_t *) asoc));
/* After sending the INIT, "A" starts the T1-init timer and
* enters the COOKIE-WAIT state.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* Process the SEND primitive.
*
* Section: 10.1 ULP-to-SCTP
* E) Send
*
* Format: SEND(association id, buffer address, byte count [,context]
* [,stream id] [,life time] [,destination transport address]
* [,unorder flag] [,no-bundle flag] [,payload protocol-id] )
* -> result
*
* This is the main method to send user data via SCTP.
*
* Mandatory attributes:
*
* o association id - local handle to the SCTP association
*
* o buffer address - the location where the user message to be
* transmitted is stored;
*
* o byte count - The size of the user data in number of bytes;
*
* Optional attributes:
*
* o context - an optional 32 bit integer that will be carried in the
* sending failure notification to the ULP if the transportation of
* this User Message fails.
*
* o stream id - to indicate which stream to send the data on. If not
* specified, stream 0 will be used.
*
* o life time - specifies the life time of the user data. The user data
* will not be sent by SCTP after the life time expires. This
* parameter can be used to avoid efforts to transmit stale
* user messages. SCTP notifies the ULP if the data cannot be
* initiated to transport (i.e. sent to the destination via SCTP's
* send primitive) within the life time variable. However, the
* user data will be transmitted if SCTP has attempted to transmit a
* chunk before the life time expired.
*
* o destination transport address - specified as one of the destination
* transport addresses of the peer endpoint to which this packet
* should be sent. Whenever possible, SCTP should use this destination
* transport address for sending the packets, instead of the current
* primary path.
*
* o unorder flag - this flag, if present, indicates that the user
* would like the data delivered in an unordered fashion to the peer
* (i.e., the U flag is set to 1 on all DATA chunks carrying this
* message).
*
* o no-bundle flag - instructs SCTP not to bundle this user data with
* other outbound DATA chunks. SCTP MAY still bundle even when
* this flag is present, when faced with network congestion.
*
* o payload protocol-id - A 32 bit unsigned integer that is to be
* passed to the peer indicating the type of payload protocol data
* being transmitted. This value is passed as opaque data by SCTP.
*
* The return value is the disposition.
*/
sctp_disposition_t sctp_sf_do_prm_send(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk));
return SCTP_DISPOSITION_CONSUME;
}
/*
* Process the SHUTDOWN primitive.
*
* Section: 10.1:
* C) Shutdown
*
* Format: SHUTDOWN(association id)
* -> result
*
* Gracefully closes an association. Any locally queued user data
* will be delivered to the peer. The association will be terminated only
* after the peer acknowledges all the SCTP packets sent. A success code
* will be returned on successful termination of the association. If
* attempting to terminate the association results in a failure, an error
* code shall be returned.
*
* Mandatory attributes:
*
* o association id - local handle to the SCTP association
*
* Optional attributes:
*
* None.
*
* The return value is the disposition.
*/
sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
int disposition;
/* From 9.2 Shutdown of an Association
* Upon receipt of the SHUTDOWN primitive from its upper
* layer, the endpoint enters SHUTDOWN-PENDING state and
* remains there until all outstanding data has been
* acknowledged by its peer. The endpoint accepts no new data
* from its upper layer, but retransmits data to the far end
* if necessary to fill gaps.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING));
/* sctpimpguide-05 Section 2.12.2
* The sender of the SHUTDOWN MAY also start an overall guard timer
* 'T5-shutdown-guard' to bound the overall time for shutdown sequence.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
disposition = SCTP_DISPOSITION_CONSUME;
if (sctp_outq_is_empty(&asoc->outqueue)) {
disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
arg, commands);
}
return disposition;
}
/*
* Process the ABORT primitive.
*
* Section: 10.1:
* C) Abort
*
* Format: Abort(association id [, cause code])
* -> result
*
* Ungracefully closes an association. Any locally queued user data
* will be discarded and an ABORT chunk is sent to the peer. A success code
* will be returned on successful abortion of the association. If
* attempting to abort the association results in a failure, an error
* code shall be returned.
*
* Mandatory attributes:
*
* o association id - local handle to the SCTP association
*
* Optional attributes:
*
* o cause code - reason of the abort to be passed to the peer
*
* None.
*
* The return value is the disposition.
*/
sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* From 9.1 Abort of an Association
* Upon receipt of the ABORT primitive from its upper
* layer, the endpoint enters CLOSED state and
* discard all outstanding data has been
* acknowledged by its peer. The endpoint accepts no new data
* from its upper layer, but retransmits data to the far end
* if necessary to fill gaps.
*/
struct msghdr *msg = arg;
sctp_chunk_t *abort;
sctp_disposition_t retval;
retval = SCTP_DISPOSITION_CONSUME;
/* Generate ABORT chunk to send the peer. */
abort = sctp_make_abort_user(asoc, NULL, msg);
if (!abort)
retval = SCTP_DISPOSITION_NOMEM;
else
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
/* Even if we can't send the ABORT due to low memory delete the
* TCB. This is a departure from our typical NOMEM handling.
*/
/* Delete the established association. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
return retval;
}
/* We tried an illegal operation on an association which is closed. */
sctp_disposition_t sctp_sf_error_closed(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_ERROR, SCTP_ERROR(-EINVAL));
return SCTP_DISPOSITION_CONSUME;
}
/* We tried an illegal operation on an association which is shutting
* down.
*/
sctp_disposition_t sctp_sf_error_shutdown(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_ERROR,
SCTP_ERROR(-ESHUTDOWN));
return SCTP_DISPOSITION_CONSUME;
}
/*
* sctp_cookie_wait_prm_shutdown
*
* Section: 4 Note: 2
* Verification Tag:
* Inputs
* (endpoint, asoc)
*
* The RFC does not explicitly address this issue, but is the route through the
* state table when someone issues a shutdown while in COOKIE_WAIT state.
*
* Outputs
* (timers)
*/
sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
}
/*
* sctp_cookie_echoed_prm_shutdown
*
* Section: 4 Note: 2
* Verification Tag:
* Inputs
* (endpoint, asoc)
*
* The RFC does not explcitly address this issue, but is the route through the
* state table when someone issues a shutdown while in COOKIE_ECHOED state.
*
* Outputs
* (timers)
*/
sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg, sctp_cmd_seq_t *commands)
{
/* There is a single T1 timer, so we should be able to use
* common function with the COOKIE-WAIT state.
*/
return sctp_sf_cookie_wait_prm_shutdown(ep, asoc, type, arg, commands);
}
/*
* sctp_sf_cookie_wait_prm_abort
*
* Section: 4 Note: 2
* Verification Tag:
* Inputs
* (endpoint, asoc)
*
* The RFC does not explicitly address this issue, but is the route through the
* state table when someone issues an abort while in COOKIE_WAIT state.
*
* Outputs
* (timers)
*/
sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
struct msghdr *msg = arg;
sctp_chunk_t *abort;
sctp_disposition_t retval;
/* Stop T1-init timer */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
retval = SCTP_DISPOSITION_CONSUME;
/* Generate ABORT chunk to send the peer */
abort = sctp_make_abort_user(asoc, NULL, msg);
if (!abort)
retval = SCTP_DISPOSITION_NOMEM;
else
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
/* Even if we can't send the ABORT due to low memory delete the
* TCB. This is a departure from our typical NOMEM handling.
*/
/* Delete the established association. */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
return retval;
}
/*
* sctp_sf_cookie_echoed_prm_abort
*
* Section: 4 Note: 3
* Verification Tag:
* Inputs
* (endpoint, asoc)
*
* The RFC does not explcitly address this issue, but is the route through the
* state table when someone issues an abort while in COOKIE_ECHOED state.
*
* Outputs
* (timers)
*/
sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* There is a single T1 timer, so we should be able to use
* common function with the COOKIE-WAIT state.
*/
return sctp_sf_cookie_wait_prm_abort(ep, asoc, type, arg, commands);
}
/*
* sctp_sf_shutdown_pending_prm_abort
*
* Inputs
* (endpoint, asoc)
*
* The RFC does not explicitly address this issue, but is the route through the
* state table when someone issues an abort while in SHUTDOWN-PENDING state.
*
* Outputs
* (timers)
*/
sctp_disposition_t sctp_sf_shutdown_pending_prm_abort(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* Stop the T5-shutdown guard timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
return sctp_sf_do_9_1_prm_abort(ep, asoc, type, arg, commands);
}
/*
* sctp_sf_shutdown_sent_prm_abort
*
* Inputs
* (endpoint, asoc)
*
* The RFC does not explicitly address this issue, but is the route through the
* state table when someone issues an abort while in SHUTDOWN-SENT state.
*
* Outputs
* (timers)
*/
sctp_disposition_t sctp_sf_shutdown_sent_prm_abort(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* Stop the T2-shutdown timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
/* Stop the T5-shutdown guard timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
return sctp_sf_do_9_1_prm_abort(ep, asoc, type, arg, commands);
}
/*
* sctp_sf_cookie_echoed_prm_abort
*
* Inputs
* (endpoint, asoc)
*
* The RFC does not explcitly address this issue, but is the route through the
* state table when someone issues an abort while in COOKIE_ECHOED state.
*
* Outputs
* (timers)
*/
sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* The same T2 timer, so we should be able to use
* common function with the SHUTDOWN-SENT state.
*/
return sctp_sf_shutdown_sent_prm_abort(ep, asoc, type, arg, commands);
}
/*
* Process the REQUESTHEARTBEAT primitive
*
* 10.1 ULP-to-SCTP
* J) Request Heartbeat
*
* Format: REQUESTHEARTBEAT(association id, destination transport address)
*
* -> result
*
* Instructs the local endpoint to perform a HeartBeat on the specified
* destination transport address of the given association. The returned
* result should indicate whether the transmission of the HEARTBEAT
* chunk to the destination address is successful.
*
* Mandatory attributes:
*
* o association id - local handle to the SCTP association
*
* o destination transport address - the transport address of the
* asociation on which a heartbeat should be issued.
*/
sctp_disposition_t sctp_sf_do_prm_requestheartbeat(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
return sctp_sf_heartbeat(ep, asoc, type, (struct sctp_transport *)arg,
commands);
}
/*
* Ignore the primitive event
*
* The return value is the disposition of the primitive.
*/
sctp_disposition_t sctp_sf_ignore_primitive(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
SCTP_DEBUG_PRINTK("Primitive type %d is ignored.\n", type.primitive);
return SCTP_DISPOSITION_DISCARD;
}
/***************************************************************************
* These are the state functions for the OTHER events.
***************************************************************************/
/*
* Start the shutdown negotiation.
*
* From Section 9.2:
* Once all its outstanding data has been acknowledged, the endpoint
* shall send a SHUTDOWN chunk to its peer including in the Cumulative
* TSN Ack field the last sequential TSN it has received from the peer.
* It shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT
* state. If the timer expires, the endpoint must re-send the SHUTDOWN
* with the updated last sequential TSN received from its peer.
*
* The return value is the disposition.
*/
sctp_disposition_t sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *reply;
/* Once all its outstanding data has been acknowledged, the
* endpoint shall send a SHUTDOWN chunk to its peer including
* in the Cumulative TSN Ack field the last sequential TSN it
* has received from the peer.
*/
reply = sctp_make_shutdown(asoc);
if (!reply)
goto nomem;
/* Set the transport for the SHUTDOWN chunk and the timeout for the
* T2-shutdown timer.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply));
/* It shall then start the T2-shutdown timer */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
if (asoc->autoclose)
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
/* and enter the SHUTDOWN-SENT state. */
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_SHUTDOWN_SENT));
/* sctp-implguide 2.10 Issues with Heartbeating and failover
*
* HEARTBEAT ... is discontinued after sending either SHUTDOWN
* or SHUTDOWN-ACK.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_STOP, SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* Generate a SHUTDOWN ACK now that everything is SACK'd.
*
* From Section 9.2:
*
* If it has no more outstanding DATA chunks, the SHUTDOWN receiver
* shall send a SHUTDOWN ACK and start a T2-shutdown timer of its own,
* entering the SHUTDOWN-ACK-SENT state. If the timer expires, the
* endpoint must re-send the SHUTDOWN ACK.
*
* The return value is the disposition.
*/
sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = (sctp_chunk_t *) arg;
sctp_chunk_t *reply;
/* If it has no more outstanding DATA chunks, the SHUTDOWN receiver
* shall send a SHUTDOWN ACK ...
*/
reply = sctp_make_shutdown_ack(asoc, chunk);
if (!reply)
goto nomem;
/* Set the transport for the SHUTDOWN ACK chunk and the timeout for
* the T2-shutdown timer.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply));
/* and start/restart a T2-shutdown timer of its own, */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
if (asoc->autoclose)
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
/* Enter the SHUTDOWN-ACK-SENT state. */
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_SHUTDOWN_ACK_SENT));
/* sctp-implguide 2.10 Issues with Heartbeating and failover
*
* HEARTBEAT ... is discontinued after sending either SHUTDOWN
* or SHUTDOWN-ACK.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_STOP, SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/*
* Ignore the event defined as other
*
* The return value is the disposition of the event.
*/
sctp_disposition_t sctp_sf_ignore_other(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
SCTP_DEBUG_PRINTK("The event other type %d is ignored\n", type.other);
return SCTP_DISPOSITION_DISCARD;
}
/************************************************************
* These are the state functions for handling timeout events.
************************************************************/
/*
* RTX Timeout
*
* Section: 6.3.3 Handle T3-rtx Expiration
*
* Whenever the retransmission timer T3-rtx expires for a destination
* address, do the following:
* [See below]
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
struct sctp_transport *transport = arg;
if (asoc->overall_error_count >= asoc->overall_error_threshold) {
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
}
/* E1) For the destination address for which the timer
* expires, adjust its ssthresh with rules defined in Section
* 7.2.3 and set the cwnd <- MTU.
*/
/* E2) For the destination address for which the timer
* expires, set RTO <- RTO * 2 ("back off the timer"). The
* maximum value discussed in rule C7 above (RTO.max) may be
* used to provide an upper bound to this doubling operation.
*/
/* E3) Determine how many of the earliest (i.e., lowest TSN)
* outstanding DATA chunks for the address for which the
* T3-rtx has expired will fit into a single packet, subject
* to the MTU constraint for the path corresponding to the
* destination transport address to which the retransmission
* is being sent (this may be different from the address for
* which the timer expires [see Section 6.4]). Call this
* value K. Bundle and retransmit those K DATA chunks in a
* single packet to the destination endpoint.
*
* Note: Any DATA chunks that were sent to the address for
* which the T3-rtx timer expired but did not fit in one MTU
* (rule E3 above), should be marked for retransmission and
* sent as soon as cwnd allows (normally when a SACK arrives).
*/
/* NB: Rules E4 and F1 are implicit in R1. */
sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(transport));
/* Do some failure management (Section 8.2). */
sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport));
return SCTP_DISPOSITION_CONSUME;
}
/*
* Generate delayed SACK on timeout
*
* Section: 6.2 Acknowledgement on Reception of DATA Chunks
*
* 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.
*/
sctp_disposition_t sctp_sf_do_6_2_sack(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE());
return SCTP_DISPOSITION_CONSUME;
}
/*
* sctp_sf_t1_timer_expire
*
* Section: 4 Note: 2
* Verification Tag:
* Inputs
* (endpoint, asoc)
*
* RFC 2960 Section 4 Notes
* 2) If the T1-init timer expires, the endpoint MUST retransmit INIT
* and re-start the T1-init timer without changing state. This MUST
* be repeated up to 'Max.Init.Retransmits' times. After that, the
* endpoint MUST abort the initialization process and report the
* error to SCTP user.
*
* 3) If the T1-cookie timer expires, the endpoint MUST retransmit
* COOKIE ECHO and re-start the T1-cookie timer without changing
* state. This MUST be repeated up to 'Max.Init.Retransmits' times.
* After that, the endpoint MUST abort the initialization process and
* report the error to SCTP user.
*
* Outputs
* (timers, events)
*
*/
sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *repl;
sctp_bind_addr_t *bp;
sctp_event_timeout_t timer = (sctp_event_timeout_t) arg;
int timeout;
int attempts;
timeout = asoc->timeouts[timer];
attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1;
repl = NULL;
SCTP_DEBUG_PRINTK("Timer T1 expired.\n");
if ((timeout < asoc->max_init_timeo) &&
(attempts < asoc->max_init_attempts)) {
switch (timer) {
case SCTP_EVENT_TIMEOUT_T1_INIT:
bp = (sctp_bind_addr_t *) &asoc->base.bind_addr;
repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0);
break;
case SCTP_EVENT_TIMEOUT_T1_COOKIE:
repl = sctp_make_cookie_echo(asoc, NULL);
break;
default:
BUG();
break;
};
if (!repl)
goto nomem;
/* Issue a sideeffect to do the needed accounting. */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_RESTART,
SCTP_TO(timer));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
} else {
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
}
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/* RFC2960 9.2 If the timer expires, the endpoint must re-send the SHUTDOWN
* with the updated last sequential TSN received from its peer.
*
* An endpoint should limit the number of retransmissions of the
* SHUTDOWN chunk to the protocol parameter 'Association.Max.Retrans'.
* If this threshold is exceeded the endpoint should destroy the TCB and
* MUST report the peer endpoint unreachable to the upper layer (and
* thus the association enters the CLOSED state). The reception of any
* packet from its peer (i.e. as the peer sends all of its queued DATA
* chunks) should clear the endpoint's retransmission count and restart
* the T2-Shutdown timer, giving its peer ample opportunity to transmit
* all of its queued DATA chunks that have not yet been sent.
*/
sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *reply = NULL;
SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
if (asoc->overall_error_count >= asoc->overall_error_threshold) {
/* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
}
switch (asoc->state) {
case SCTP_STATE_SHUTDOWN_SENT:
reply = sctp_make_shutdown(asoc);
break;
case SCTP_STATE_SHUTDOWN_ACK_SENT:
reply = sctp_make_shutdown_ack(asoc, NULL);
break;
default:
BUG();
break;
};
if (!reply)
goto nomem;
/* Do some failure management (Section 8.2). */
sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE,
SCTP_TRANSPORT(asoc->shutdown_last_sent_to));
/* Set the transport for the SHUTDOWN/ACK chunk and the timeout for
* the T2-shutdown timer.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply));
/* Restart the T2-shutdown timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/* sctpimpguide-05 Section 2.12.2
* The sender of the SHUTDOWN MAY also start an overall guard timer
* 'T5-shutdown-guard' to bound the overall time for shutdown sequence.
* At the expiration of this timer the sender SHOULD abort the association
* by sending an ABORT chunk.
*/
sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *reply = NULL;
SCTP_DEBUG_PRINTK("Timer T5 expired.\n");
reply = sctp_make_abort(asoc, NULL, 0);
if (!reply)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/* Handle expiration of AUTOCLOSE timer. When the autoclose timer expires,
* the association is automatically closed by starting the shutdown process.
* The work that needs to be done is same as when SHUTDOWN is initiated by
* the user. So this routine looks same as sctp_sf_do_9_2_prm_shutdown().
*/
sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
int disposition;
/* From 9.2 Shutdown of an Association
* Upon receipt of the SHUTDOWN primitive from its upper
* layer, the endpoint enters SHUTDOWN-PENDING state and
* remains there until all outstanding data has been
* acknowledged by its peer. The endpoint accepts no new data
* from its upper layer, but retransmits data to the far end
* if necessary to fill gaps.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING));
/* sctpimpguide-05 Section 2.12.2
* The sender of the SHUTDOWN MAY also start an overall guard timer
* 'T5-shutdown-guard' to bound the overall time for shutdown sequence.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
disposition = SCTP_DISPOSITION_CONSUME;
if (sctp_outq_is_empty(&asoc->outqueue)) {
disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
arg, commands);
}
return disposition;
}
/*****************************************************************************
* These are sa state functions which could apply to all types of events.
****************************************************************************/
/*
* This table entry is not implemented.
*
* Inputs
* (endpoint, asoc, chunk)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_not_impl(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
return SCTP_DISPOSITION_NOT_IMPL;
}
/*
* This table entry represents a bug.
*
* Inputs
* (endpoint, asoc, chunk)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_bug(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
return SCTP_DISPOSITION_BUG;
}
/*
* This table entry represents the firing of a timer in the wrong state.
* Since timer deletion cannot be guaranteed a timer 'may' end up firing
* when the association is in the wrong state. This event should
* be ignored, so as to prevent any rearming of the timer.
*
* Inputs
* (endpoint, asoc, chunk)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_timer_ignore(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
SCTP_DEBUG_PRINTK("Timer %d ignored.\n", type.chunk);
return SCTP_DISPOSITION_CONSUME;
}
/********************************************************************
* 2nd Level Abstractions
********************************************************************/
/* Pull the SACK chunk based on the SACK header. */
sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk)
{
sctp_sackhdr_t *sack;
__u16 num_blocks;
__u16 num_dup_tsns;
sack = (sctp_sackhdr_t *) chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_sackhdr_t));
num_blocks = ntohs(sack->num_gap_ack_blocks);
num_dup_tsns = ntohs(sack->num_dup_tsns);
skb_pull(chunk->skb, (num_blocks + num_dup_tsns) * sizeof(__u32));
return sack;
}
/* Create an ABORT packet to be sent as a response, with the specified
* error causes.
*/
sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
sctp_chunk_t *chunk,
const void *payload,
size_t paylen)
{
sctp_packet_t *packet;
sctp_chunk_t *abort;
packet = sctp_ootb_pkt_new(asoc, chunk);
if (packet) {
/* Make an ABORT.
* The T bit will be set if the asoc is NULL.
*/
abort = sctp_make_abort(asoc, chunk, paylen);
if (!abort) {
sctp_ootb_pkt_free(packet);
return NULL;
}
/* Add specified error causes, i.e., payload, to the
* end of the chunk.
*/
sctp_addto_chunk(abort, paylen, payload);
/* Set the skb to the belonging sock for accounting. */
abort->skb->sk = ep->base.sk;
sctp_packet_append_chunk(packet, abort);
}
return packet;
}
/* Allocate a packet for responding in the OOTB conditions. */
sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
const sctp_chunk_t *chunk)
{
sctp_packet_t *packet;
struct sctp_transport *transport;
__u16 sport;
__u16 dport;
__u32 vtag;
/* Get the source and destination port from the inbound packet. */
sport = ntohs(chunk->sctp_hdr->dest);
dport = ntohs(chunk->sctp_hdr->source);
/* The V-tag is going to be the same as the inbound packet if no
* association exists, otherwise, use the peer's vtag.
*/
if (asoc) {
vtag = asoc->peer.i.init_tag;
} else {
/* Special case the INIT as there is no vtag yet. */
if (SCTP_CID_INIT == chunk->chunk_hdr->type) {
sctp_init_chunk_t *init;
init = (sctp_init_chunk_t *)chunk->chunk_hdr;
vtag = ntohl(init->init_hdr.init_tag);
} else {
vtag = ntohl(chunk->sctp_hdr->vtag);
}
}
/* Make a transport for the bucket, Eliza... */
transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC);
if (!transport)
goto nomem;
/* Allocate a new packet for sending the response. */
packet = t_new(sctp_packet_t, GFP_ATOMIC);
if (!packet)
goto nomem_packet;
/* Cache a route for the transport with the chunk's destination as
* the source address.
*/
sctp_transport_route(transport, (union sctp_addr *)&chunk->dest,
sctp_sk(sctp_get_ctl_sock()));
packet = sctp_packet_init(packet, transport, sport, dport);
packet = sctp_packet_config(packet, vtag, 0, NULL);
return packet;
nomem_packet:
sctp_transport_free(transport);
nomem:
return NULL;
}
/* Free the packet allocated earlier for responding in the OOTB condition. */
void sctp_ootb_pkt_free(sctp_packet_t *packet)
{
sctp_transport_free(packet->transport);
sctp_packet_free(packet);
}
/* Send a stale cookie error when a invalid COOKIE ECHO chunk is found */
void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_chunk_t *chunk,
sctp_cmd_seq_t *commands,
sctp_chunk_t *err_chunk)
{
sctp_packet_t *packet;
if (err_chunk) {
packet = sctp_ootb_pkt_new(asoc, chunk);
if (packet) {
/* Set the skb to the belonging sock for accounting. */
err_chunk->skb->sk = ep->base.sk;
sctp_packet_append_chunk(packet, err_chunk);
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
SCTP_PACKET(packet));
} else
sctp_free_chunk (err_chunk);
}
}