patch-2.4.26 linux-2.4.26/net/sctp/sm_sideeffect.c
Next file: linux-2.4.26/net/sctp/sm_statefuns.c
Previous file: linux-2.4.26/net/sctp/sm_make_chunk.c
Back to the patch index
Back to the overall index
- Lines: 372
- Date:
2004-04-14 06:05:41.000000000 -0700
- Orig file:
linux-2.4.25/net/sctp/sm_sideeffect.c
- Orig date:
2003-11-28 10:26:21.000000000 -0800
diff -urN linux-2.4.25/net/sctp/sm_sideeffect.c linux-2.4.26/net/sctp/sm_sideeffect.c
@@ -1,7 +1,7 @@
/* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001-2002 International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
@@ -81,11 +81,11 @@
* This element represents the lowest TSN number in the datagram
* that was originally marked with the CE bit.
*/
-static sctp_chunk_t *sctp_do_ecn_ecne_work(struct sctp_association *asoc,
+static struct sctp_chunk *sctp_do_ecn_ecne_work(struct sctp_association *asoc,
__u32 lowest_tsn,
- sctp_chunk_t *chunk)
+ struct sctp_chunk *chunk)
{
- sctp_chunk_t *repl;
+ struct sctp_chunk *repl;
/* Our previously transmitted packet ran into some congestion
* so we should take action by reducing cwnd and ssthresh
@@ -229,7 +229,7 @@
transport, GFP_ATOMIC);
if (error)
- asoc->base.sk->err = -error;
+ asoc->base.sk->sk_err = -error;
out_unlock:
sctp_bh_unlock_sock(asoc->base.sk);
@@ -269,7 +269,7 @@
(void *)timeout_type, GFP_ATOMIC);
if (error)
- asoc->base.sk->err = -error;
+ asoc->base.sk->sk_err = -error;
out_unlock:
sctp_bh_unlock_sock(asoc->base.sk);
@@ -294,6 +294,12 @@
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN);
}
+void sctp_generate_t4_rto_event(unsigned long data)
+{
+ struct sctp_association *asoc = (struct sctp_association *) data;
+ sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T4_RTO);
+}
+
void sctp_generate_t5_shutdown_guard_event(unsigned long data)
{
struct sctp_association *asoc = (struct sctp_association *)data;
@@ -339,7 +345,7 @@
transport, GFP_ATOMIC);
if (error)
- asoc->base.sk->err = -error;
+ asoc->base.sk->sk_err = -error;
out_unlock:
sctp_bh_unlock_sock(asoc->base.sk);
@@ -359,6 +365,7 @@
sctp_generate_t1_init_event,
sctp_generate_t2_shutdown_event,
NULL,
+ sctp_generate_t4_rto_event,
sctp_generate_t5_shutdown_guard_event,
sctp_generate_heartbeat_event,
sctp_generate_sack_event,
@@ -415,7 +422,8 @@
struct sctp_ulpevent *event;
event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC,
- 0, 0, 0, GFP_ATOMIC);
+ (__u16)error, 0, 0,
+ GFP_ATOMIC);
if (event)
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
@@ -528,7 +536,7 @@
static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
struct sctp_association *asoc,
struct sctp_transport *t,
- sctp_chunk_t *chunk)
+ struct sctp_chunk *chunk)
{
sctp_sender_hb_info_t *hbinfo;
@@ -596,7 +604,7 @@
*/
static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds,
struct sctp_association *asoc,
- sctp_chunk_t *chunk)
+ struct sctp_chunk *chunk)
{
struct sctp_transport *t;
@@ -607,33 +615,30 @@
}
/* Helper function to change the state of an association. */
-static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, struct sctp_association *asoc,
+static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds,
+ struct sctp_association *asoc,
sctp_state_t state)
{
-
struct sock *sk = asoc->base.sk;
- struct sctp_opt *sp = sctp_sk(sk);
asoc->state = state;
- asoc->state_timestamp = jiffies;
- if (SCTP_SOCKET_TCP == sp->type) {
- /* Change the sk->state of a TCP-style socket that has
+ if (sctp_style(sk, TCP)) {
+ /* Change the sk->sk_state of a TCP-style socket that has
* sucessfully completed a connect() call.
*/
- if ((SCTP_STATE_ESTABLISHED == asoc->state) &&
- (SCTP_SS_CLOSED == sk->state))
- sk->state = SCTP_SS_ESTABLISHED;
+ if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED))
+ sk->sk_state = SCTP_SS_ESTABLISHED;
/* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */
- if (SCTP_STATE_SHUTDOWN_RECEIVED == asoc->state)
- sk->shutdown |= RCV_SHUTDOWN;
-
+ if (sctp_state(asoc, SHUTDOWN_RECEIVED) &&
+ sctp_sstate(sk, ESTABLISHED))
+ sk->sk_shutdown |= RCV_SHUTDOWN;
}
- if ((SCTP_STATE_ESTABLISHED == asoc->state) ||
- (SCTP_STATE_CLOSED == asoc->state) ||
- (SCTP_STATE_SHUTDOWN_RECEIVED == asoc->state)) {
+ if (sctp_state(asoc, ESTABLISHED) ||
+ sctp_state(asoc, CLOSED) ||
+ sctp_state(asoc, SHUTDOWN_RECEIVED)) {
/* Wake up any processes waiting in the asoc's wait queue in
* sctp_wait_for_connect() or sctp_wait_for_sndbuf().
*/
@@ -646,30 +651,84 @@
* For a UDP-style socket, the waiters are woken up by the
* notifications.
*/
- if (SCTP_SOCKET_UDP != sp->type)
- sk->state_change(sk);
+ if (!sctp_style(sk, UDP))
+ sk->sk_state_change(sk);
}
-
}
/* Helper function to delete an association. */
static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds,
- struct sctp_association *asoc)
+ struct sctp_association *asoc)
{
struct sock *sk = asoc->base.sk;
/* If it is a non-temporary association belonging to a TCP-style
- * listening socket, do not free it so that accept() can pick it
- * up later.
- */
- if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
- (SCTP_SS_LISTENING == sk->state) && (!asoc->temp))
+ * listening socket that is not closed, do not free it so that accept()
+ * can pick it up later.
+ */
+ if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) &&
+ (!asoc->temp) && (sk->sk_shutdown != SHUTDOWN_MASK))
return;
sctp_unhash_established(asoc);
sctp_association_free(asoc);
}
+/*
+ * ADDIP Section 4.1 ASCONF Chunk Procedures
+ * A4) Start a T-4 RTO timer, using the RTO value of the selected
+ * destination address (we use active path instead of primary path just
+ * because primary path may be inactive.
+ */
+static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds,
+ struct sctp_association *asoc,
+ struct sctp_chunk *chunk)
+{
+ struct sctp_transport *t;
+
+ t = asoc->peer.active_path;
+ asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = t->rto;
+ chunk->transport = t;
+}
+
+/* Process an incoming Operation Error Chunk. */
+static void sctp_cmd_process_operr(sctp_cmd_seq_t *cmds,
+ struct sctp_association *asoc,
+ struct sctp_chunk *chunk)
+{
+ struct sctp_operr_chunk *operr_chunk;
+ struct sctp_errhdr *err_hdr;
+
+ operr_chunk = (struct sctp_operr_chunk *)chunk->chunk_hdr;
+ err_hdr = &operr_chunk->err_hdr;
+
+ switch (err_hdr->cause) {
+ case SCTP_ERROR_UNKNOWN_CHUNK:
+ {
+ struct sctp_chunkhdr *unk_chunk_hdr;
+
+ unk_chunk_hdr = (struct sctp_chunkhdr *)err_hdr->variable;
+ switch (unk_chunk_hdr->type) {
+ /* ADDIP 4.1 A9) If the peer responds to an ASCONF with an
+ * ERROR chunk reporting that it did not recognized the ASCONF
+ * chunk type, the sender of the ASCONF MUST NOT send any
+ * further ASCONF chunks and MUST stop its T-4 timer.
+ */
+ case SCTP_CID_ASCONF:
+ asoc->peer.asconf_capable = 0;
+ sctp_add_cmd_sf(cmds, SCTP_CMD_TIMER_STOP,
+ SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
/* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real
* functionality there.
@@ -706,7 +765,7 @@
int gfp)
{
sctp_cmd_seq_t commands;
- sctp_sm_table_entry_t *state_fn;
+ const sctp_sm_table_entry_t *state_fn;
sctp_disposition_t status;
int error = 0;
typedef const char *(printfn_t)(sctp_subtype_t);
@@ -837,17 +896,18 @@
int error = 0;
int force;
sctp_cmd_t *cmd;
- sctp_chunk_t *new_obj;
- sctp_chunk_t *chunk = NULL;
+ struct sctp_chunk *new_obj;
+ struct sctp_chunk *chunk = NULL;
struct sctp_packet *packet;
struct list_head *pos;
struct timer_list *timer;
unsigned long timeout;
struct sctp_transport *t;
sctp_sackhdr_t sackh;
+ int local_cork = 0;
- if(SCTP_EVENT_T_TIMEOUT != event_type)
- chunk = (sctp_chunk_t *) event_arg;
+ if (SCTP_EVENT_T_TIMEOUT != event_type)
+ chunk = (struct sctp_chunk *) event_arg;
/* Note: This whole file is a huge candidate for rework.
* For example, each command could either have its own handler, so
@@ -864,6 +924,10 @@
case SCTP_CMD_NEW_ASOC:
/* Register a new association. */
+ if (local_cork) {
+ sctp_outq_uncork(&asoc->outqueue);
+ local_cork = 0;
+ }
asoc = cmd->obj.ptr;
/* Register with the endpoint. */
sctp_endpoint_add_asoc(ep, asoc);
@@ -878,7 +942,11 @@
sctp_outq_teardown(&asoc->outqueue);
break;
- case SCTP_CMD_DELETE_TCB:
+ case SCTP_CMD_DELETE_TCB:
+ if (local_cork) {
+ sctp_outq_uncork(&asoc->outqueue);
+ local_cork = 0;
+ }
/* Delete the current association. */
sctp_cmd_delete_tcb(commands, asoc);
asoc = NULL;
@@ -936,7 +1004,7 @@
new_obj = sctp_make_cookie_echo(asoc, chunk);
if (!new_obj) {
if (cmd->obj.ptr)
- sctp_free_chunk(cmd->obj.ptr);
+ sctp_chunk_free(cmd->obj.ptr);
goto nomem;
}
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
@@ -957,7 +1025,7 @@
asoc->overall_error_count = 0;
/* Generate a SHUTDOWN chunk. */
- new_obj = sctp_make_shutdown(asoc);
+ new_obj = sctp_make_shutdown(asoc, chunk);
if (!new_obj)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
@@ -982,9 +1050,13 @@
break;
case SCTP_CMD_REPLY:
+ /* If an caller has not already corked, do cork. */
+ if (!asoc->outqueue.cork) {
+ sctp_outq_cork(&asoc->outqueue);
+ local_cork = 1;
+ }
/* Send a chunk to our peer. */
- error = sctp_outq_tail(&asoc->outqueue,
- cmd->obj.ptr);
+ error = sctp_outq_tail(&asoc->outqueue, cmd->obj.ptr);
break;
case SCTP_CMD_SEND_PKT:
@@ -1002,7 +1074,8 @@
case SCTP_CMD_TRANSMIT:
/* Kick start transmission. */
- error = sctp_outq_flush(&asoc->outqueue, 0);
+ error = sctp_outq_uncork(&asoc->outqueue);
+ local_cork = 0;
break;
case SCTP_CMD_ECN_CE:
@@ -1167,19 +1240,28 @@
GFP_ATOMIC);
break;
+ case SCTP_CMD_SETUP_T4:
+ sctp_cmd_setup_t4(commands, asoc, cmd->obj.ptr);
+ break;
+
+ case SCTP_CMD_PROCESS_OPERR:
+ sctp_cmd_process_operr(commands, asoc, chunk);
+ break;
default:
printk(KERN_WARNING "Impossible command: %u, %p\n",
cmd->verb, cmd->obj.ptr);
break;
};
if (error)
- return error;
+ break;
}
+out:
+ if (local_cork)
+ sctp_outq_uncork(&asoc->outqueue);
return error;
-
nomem:
error = -ENOMEM;
- return error;
+ goto out;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)