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

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)