diff options
Diffstat (limited to 'net/sctp/sm_sideeffect.c')
| -rw-r--r-- | net/sctp/sm_sideeffect.c | 64 | 
1 files changed, 63 insertions, 1 deletions
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 4e4ca65cd32..eb1f42f45fd 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -51,6 +51,7 @@  #include <linux/types.h>  #include <linux/socket.h>  #include <linux/ip.h> +#include <linux/gfp.h>  #include <net/sock.h>  #include <net/sctp/sctp.h>  #include <net/sctp/sm.h> @@ -396,6 +397,41 @@ out_unlock:  	sctp_transport_put(transport);  } +/* Handle the timeout of the ICMP protocol unreachable timer.  Trigger + * the correct state machine transition that will close the association. + */ +void sctp_generate_proto_unreach_event(unsigned long data) +{ +	struct sctp_transport *transport = (struct sctp_transport *) data; +	struct sctp_association *asoc = transport->asoc; +	 +	sctp_bh_lock_sock(asoc->base.sk); +	if (sock_owned_by_user(asoc->base.sk)) { +		SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__); + +		/* Try again later.  */ +		if (!mod_timer(&transport->proto_unreach_timer, +				jiffies + (HZ/20))) +			sctp_association_hold(asoc); +		goto out_unlock; +	} + +	/* Is this structure just waiting around for us to actually +	 * get destroyed? +	 */ +	if (asoc->base.dead) +		goto out_unlock; + +	sctp_do_sm(SCTP_EVENT_T_OTHER, +		   SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH), +		   asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC); + +out_unlock: +	sctp_bh_unlock_sock(asoc->base.sk); +	sctp_association_put(asoc); +} + +  /* Inject a SACK Timeout event into the state machine.  */  static void sctp_generate_sack_event(unsigned long data)  { @@ -475,7 +511,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,  	 * used to provide an upper bound to this doubling operation.  	 *  	 * Special Case:  the first HB doesn't trigger exponential backoff. -	 * The first unacknowleged HB triggers it.  We do this with a flag +	 * The first unacknowledged HB triggers it.  We do this with a flag  	 * that indicates that we have an outstanding HB.  	 */  	if (!is_hb || transport->hb_sent) { @@ -961,6 +997,29 @@ static int sctp_cmd_send_msg(struct sctp_association *asoc,  } +/* Sent the next ASCONF packet currently stored in the association. + * This happens after the ASCONF_ACK was succeffully processed. + */ +static void sctp_cmd_send_asconf(struct sctp_association *asoc) +{ +	/* Send the next asconf chunk from the addip chunk +	 * queue. +	 */ +	if (!list_empty(&asoc->addip_chunk_list)) { +		struct list_head *entry = asoc->addip_chunk_list.next; +		struct sctp_chunk *asconf = list_entry(entry, +						struct sctp_chunk, list); +		list_del_init(entry); + +		/* Hold the chunk until an ASCONF_ACK is received. */ +		sctp_chunk_hold(asconf); +		if (sctp_primitive_ASCONF(asoc, asconf)) +			sctp_chunk_free(asconf); +		else +			asoc->addip_last_asconf = asconf; +	} +} +  /* 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 @@ -1616,6 +1675,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,  			}  			error = sctp_cmd_send_msg(asoc, cmd->obj.msg);  			break; +		case SCTP_CMD_SEND_NEXT_ASCONF: +			sctp_cmd_send_asconf(asoc); +			break;  		default:  			printk(KERN_WARNING "Impossible command: %u, %p\n",  			       cmd->verb, cmd->obj.ptr);  |