17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2177c67f2fSkcpoon 
227c478bd9Sstevel@tonic-gate /*
23fd7b5aedSGeorge Shepherd  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/systm.h>
287c478bd9Sstevel@tonic-gate #include <sys/stream.h>
297c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
307c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
317c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <netinet/in.h>
347c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <inet/common.h>
377c478bd9Sstevel@tonic-gate #include <inet/ip.h>
387c478bd9Sstevel@tonic-gate #include <inet/mib2.h>
397c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h>
407c478bd9Sstevel@tonic-gate #include "sctp_impl.h"
417c478bd9Sstevel@tonic-gate #include "sctp_asconf.h"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /* Timer block states. */
447c478bd9Sstevel@tonic-gate typedef enum {
457c478bd9Sstevel@tonic-gate 	SCTP_TB_RUNNING = 1,
467c478bd9Sstevel@tonic-gate 	SCTP_TB_IDLE,
477c478bd9Sstevel@tonic-gate /* Could not stop/free before mblk got queued */
487c478bd9Sstevel@tonic-gate 	SCTP_TB_RESCHED,	/* sctp_tb_time_left contains tick count */
497c478bd9Sstevel@tonic-gate 	SCTP_TB_CANCELLED,
507c478bd9Sstevel@tonic-gate 	SCTP_TB_TO_BE_FREED
517c478bd9Sstevel@tonic-gate } timer_block_state;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate typedef struct sctp_tb_s {
547c478bd9Sstevel@tonic-gate 	timer_block_state	sctp_tb_state;
557c478bd9Sstevel@tonic-gate 	timeout_id_t		sctp_tb_tid;
567c478bd9Sstevel@tonic-gate 	mblk_t			*sctp_tb_mp;
577c478bd9Sstevel@tonic-gate 	clock_t			sctp_tb_time_left;
587c478bd9Sstevel@tonic-gate } sctp_tb_t;
597c478bd9Sstevel@tonic-gate 
605dd46ab5SKacheong Poon /*
615dd46ab5SKacheong Poon  * Early abort threshold when the system is under pressure, sctps_reclaim
625dd46ab5SKacheong Poon  * is on.
635dd46ab5SKacheong Poon  *
645dd46ab5SKacheong Poon  * sctp_pa_early_abort: number of strikes per association before abort
655dd46ab5SKacheong Poon  * sctp_pp_early_abort: number of strikes per peer address before abort
665dd46ab5SKacheong Poon  */
675dd46ab5SKacheong Poon uint32_t sctp_pa_early_abort = 5;
685dd46ab5SKacheong Poon uint32_t sctp_pp_early_abort = 3;
695dd46ab5SKacheong Poon 
707c478bd9Sstevel@tonic-gate static void sctp_timer_fire(sctp_tb_t *);
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate /*
737c478bd9Sstevel@tonic-gate  *		sctp_timer mechanism.
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  * Each timer is represented by a timer mblk. When the
767c478bd9Sstevel@tonic-gate  * timer fires, and the sctp_t is busy, the timer mblk will be put on
777c478bd9Sstevel@tonic-gate  * the associated sctp_t timer queue so that it can be executed when
787c478bd9Sstevel@tonic-gate  * the thread holding the lock on the sctp_t is done with its job.
797c478bd9Sstevel@tonic-gate  *
807c478bd9Sstevel@tonic-gate  * Note that there is no lock to protect the timer mblk state.  The reason
817c478bd9Sstevel@tonic-gate  * is that the timer state can only be changed by a thread holding the
827c478bd9Sstevel@tonic-gate  * lock on the sctp_t.
837c478bd9Sstevel@tonic-gate  *
847c478bd9Sstevel@tonic-gate  * The interface consists of 4 entry points:
857c478bd9Sstevel@tonic-gate  *	sctp_timer_alloc	- create a timer mblk
867c478bd9Sstevel@tonic-gate  *	sctp_timer_free		- free a timer mblk
877c478bd9Sstevel@tonic-gate  *	sctp_timer		- start, restart, stop the timer
887c478bd9Sstevel@tonic-gate  *	sctp_timer_valid	- called by sctp_process_recvq to verify that
897c478bd9Sstevel@tonic-gate  *				  the timer did indeed fire.
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * Start, restart, stop the timer.
957c478bd9Sstevel@tonic-gate  * If "tim" is -1 the timer is stopped.
967c478bd9Sstevel@tonic-gate  * Otherwise, the timer is stopped if it is already running, and
977c478bd9Sstevel@tonic-gate  * set to fire tim clock ticks from now.
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate void
1007c478bd9Sstevel@tonic-gate sctp_timer(sctp_t *sctp, mblk_t *mp, clock_t tim)
1017c478bd9Sstevel@tonic-gate {
1027c478bd9Sstevel@tonic-gate 	sctp_tb_t *sctp_tb;
1037c478bd9Sstevel@tonic-gate 	int state;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	ASSERT(sctp != NULL && mp != NULL);
1067c478bd9Sstevel@tonic-gate 	ASSERT((mp->b_rptr - mp->b_datap->db_base) == sizeof (sctp_tb_t));
1077c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_PCSIG);
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	sctp_tb = (sctp_tb_t *)mp->b_datap->db_base;
1107c478bd9Sstevel@tonic-gate 	if (tim >= 0) {
1117c478bd9Sstevel@tonic-gate 		state = sctp_tb->sctp_tb_state;
1127c478bd9Sstevel@tonic-gate 		sctp_tb->sctp_tb_time_left = tim;
1137c478bd9Sstevel@tonic-gate 		if (state == SCTP_TB_RUNNING) {
1147c478bd9Sstevel@tonic-gate 			if (untimeout(sctp_tb->sctp_tb_tid) < 0) {
1157c478bd9Sstevel@tonic-gate 				sctp_tb->sctp_tb_state = SCTP_TB_RESCHED;
1167c478bd9Sstevel@tonic-gate 				/* sctp_timer_valid will start timer */
1177c478bd9Sstevel@tonic-gate 				return;
1187c478bd9Sstevel@tonic-gate 			}
1197c478bd9Sstevel@tonic-gate 		} else if (state != SCTP_TB_IDLE) {
1207c478bd9Sstevel@tonic-gate 			ASSERT(state != SCTP_TB_TO_BE_FREED);
1217c478bd9Sstevel@tonic-gate 			if (state == SCTP_TB_CANCELLED) {
1227c478bd9Sstevel@tonic-gate 				sctp_tb->sctp_tb_state = SCTP_TB_RESCHED;
1237c478bd9Sstevel@tonic-gate 				/* sctp_timer_valid will start timer */
1247c478bd9Sstevel@tonic-gate 				return;
1257c478bd9Sstevel@tonic-gate 			}
1267c478bd9Sstevel@tonic-gate 			if (state == SCTP_TB_RESCHED) {
1277c478bd9Sstevel@tonic-gate 				/* sctp_timer_valid will start timer */
1287c478bd9Sstevel@tonic-gate 				return;
1297c478bd9Sstevel@tonic-gate 			}
1307c478bd9Sstevel@tonic-gate 		} else {
1317c478bd9Sstevel@tonic-gate 			SCTP_REFHOLD(sctp);
1327c478bd9Sstevel@tonic-gate 		}
1337c478bd9Sstevel@tonic-gate 		sctp_tb->sctp_tb_state = SCTP_TB_RUNNING;
1347c478bd9Sstevel@tonic-gate 		sctp_tb->sctp_tb_tid =
1357c478bd9Sstevel@tonic-gate 		    timeout((pfv_t)sctp_timer_fire, sctp_tb, tim);
1367c478bd9Sstevel@tonic-gate 		return;
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate 	switch (tim) {
1397c478bd9Sstevel@tonic-gate 	case -1:
1407c478bd9Sstevel@tonic-gate 		sctp_timer_stop(mp);
1417c478bd9Sstevel@tonic-gate 		break;
1427c478bd9Sstevel@tonic-gate 	default:
1437c478bd9Sstevel@tonic-gate 		ASSERT(0);
1447c478bd9Sstevel@tonic-gate 		break;
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * sctp_timer_alloc is called by sctp_init to allocate and initialize a
1507c478bd9Sstevel@tonic-gate  * sctp timer.
1517c478bd9Sstevel@tonic-gate  *
1527c478bd9Sstevel@tonic-gate  * Allocate an M_PCSIG timer message. The space between db_base and
1537c478bd9Sstevel@tonic-gate  * b_rptr is used by the sctp_timer mechanism, and after b_rptr there is
1547c478bd9Sstevel@tonic-gate  * space for sctpt_t.
1557c478bd9Sstevel@tonic-gate  */
1567c478bd9Sstevel@tonic-gate mblk_t *
157121e5416Skcpoon sctp_timer_alloc(sctp_t *sctp, pfv_t func, int sleep)
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate 	mblk_t *mp;
1607c478bd9Sstevel@tonic-gate 	sctp_tb_t *sctp_tb;
1617c478bd9Sstevel@tonic-gate 	sctpt_t	*sctpt;
162f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
1637c478bd9Sstevel@tonic-gate 
164121e5416Skcpoon 	if (sleep == KM_SLEEP) {
165121e5416Skcpoon 		mp = allocb_wait(sizeof (sctp_t) + sizeof (sctp_tb_t), BPRI_HI,
166121e5416Skcpoon 		    STR_NOSIG, NULL);
167121e5416Skcpoon 	} else {
168121e5416Skcpoon 		mp = allocb(sizeof (sctp_t) + sizeof (sctp_tb_t), BPRI_HI);
169121e5416Skcpoon 	}
170121e5416Skcpoon 	if (mp != NULL) {
1717c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PCSIG;
1727c478bd9Sstevel@tonic-gate 		sctp_tb = (sctp_tb_t *)mp->b_datap->db_base;
1737c478bd9Sstevel@tonic-gate 		mp->b_rptr = (uchar_t *)&sctp_tb[1];
1747c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + sizeof (sctpt_t);
1757c478bd9Sstevel@tonic-gate 		sctp_tb->sctp_tb_state = SCTP_TB_IDLE;
1767c478bd9Sstevel@tonic-gate 		sctp_tb->sctp_tb_mp = mp;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 		sctpt = (sctpt_t *)mp->b_rptr;
1797c478bd9Sstevel@tonic-gate 		sctpt->sctpt_sctp = sctp;
1807c478bd9Sstevel@tonic-gate 		sctpt->sctpt_faddr = NULL;	/* set when starting timer */
1817c478bd9Sstevel@tonic-gate 		sctpt->sctpt_pfv = func;
1827c478bd9Sstevel@tonic-gate 		return (mp);
1837c478bd9Sstevel@tonic-gate 	}
184f4b3ec61Sdh 	SCTP_KSTAT(sctps, sctp_add_timer);
1857c478bd9Sstevel@tonic-gate 	return (NULL);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * timeout() callback function.
1907c478bd9Sstevel@tonic-gate  * Put the message on the process control block's queue.
1917c478bd9Sstevel@tonic-gate  * If the timer is stopped or freed after
1927c478bd9Sstevel@tonic-gate  * it has fired then sctp_timer() and sctp_timer_valid() will clean
1937c478bd9Sstevel@tonic-gate  * things up.
1947c478bd9Sstevel@tonic-gate  */
1957c478bd9Sstevel@tonic-gate static void
1967c478bd9Sstevel@tonic-gate sctp_timer_fire(sctp_tb_t *sctp_tb)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate 	mblk_t *mp;
1997c478bd9Sstevel@tonic-gate 	sctp_t *sctp;
2007c478bd9Sstevel@tonic-gate 	sctpt_t *sctpt;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	mp = sctp_tb->sctp_tb_mp;
2037c478bd9Sstevel@tonic-gate 	ASSERT(sctp_tb == (sctp_tb_t *)mp->b_datap->db_base);
2047c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_PCSIG);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	sctpt = (sctpt_t *)mp->b_rptr;
2077c478bd9Sstevel@tonic-gate 	sctp = sctpt->sctpt_sctp;
2087c478bd9Sstevel@tonic-gate 	ASSERT(sctp != NULL);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	mutex_enter(&sctp->sctp_lock);
2117c478bd9Sstevel@tonic-gate 	if (sctp->sctp_running) {
2127c478bd9Sstevel@tonic-gate 		/*
2137c478bd9Sstevel@tonic-gate 		 * Put the timer mblk to the special sctp_timer_mp list.
2147c478bd9Sstevel@tonic-gate 		 * This timer will be handled when the thread using this
2157c478bd9Sstevel@tonic-gate 		 * SCTP is done with its job.
2167c478bd9Sstevel@tonic-gate 		 */
2177c478bd9Sstevel@tonic-gate 		if (sctp->sctp_timer_mp == NULL) {
2187c478bd9Sstevel@tonic-gate 			SCTP_REFHOLD(sctp);
2197c478bd9Sstevel@tonic-gate 			sctp->sctp_timer_mp = mp;
2207c478bd9Sstevel@tonic-gate 		} else {
2217c478bd9Sstevel@tonic-gate 			linkb(sctp->sctp_timer_mp, mp);
2227c478bd9Sstevel@tonic-gate 		}
2237c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
2247c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_lock);
2257c478bd9Sstevel@tonic-gate 	} else {
2267c478bd9Sstevel@tonic-gate 		sctp->sctp_running = B_TRUE;
2277c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_lock);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 		sctp_timer_call(sctp, mp);
2307c478bd9Sstevel@tonic-gate 		WAKE_SCTP(sctp);
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 	SCTP_REFRELE(sctp);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate  * Logically free a timer mblk (that might have a pending timeout().)
2377c478bd9Sstevel@tonic-gate  * If the timer has fired and the mblk has been put on the queue then
2387c478bd9Sstevel@tonic-gate  * sctp_timer_valid will free the mblk.
2397c478bd9Sstevel@tonic-gate  */
2407c478bd9Sstevel@tonic-gate void
2417c478bd9Sstevel@tonic-gate sctp_timer_free(mblk_t *mp)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 	sctp_tb_t *sctp_tb;
2447c478bd9Sstevel@tonic-gate 	int state;
2457c478bd9Sstevel@tonic-gate 	sctpt_t *sctpt;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
2487c478bd9Sstevel@tonic-gate 	ASSERT((mp->b_rptr - mp->b_datap->db_base) == sizeof (sctp_tb_t));
2497c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_PCSIG);
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	sctp_tb = (sctp_tb_t *)mp->b_datap->db_base;
2527c478bd9Sstevel@tonic-gate 	state = sctp_tb->sctp_tb_state;
2537c478bd9Sstevel@tonic-gate 
25445916cd2Sjpk 	dprint(5, ("sctp_timer_free %p state %d\n", (void *)mp, state));
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	if (state == SCTP_TB_RUNNING) {
2577c478bd9Sstevel@tonic-gate 		if (untimeout(sctp_tb->sctp_tb_tid) < 0) {
2587c478bd9Sstevel@tonic-gate 			sctp_tb->sctp_tb_state = SCTP_TB_TO_BE_FREED;
2597c478bd9Sstevel@tonic-gate 			/* sctp_timer_valid will free the mblk */
2607c478bd9Sstevel@tonic-gate 			return;
2617c478bd9Sstevel@tonic-gate 		}
2627c478bd9Sstevel@tonic-gate 		sctpt = (sctpt_t *)mp->b_rptr;
2637c478bd9Sstevel@tonic-gate 		SCTP_REFRELE(sctpt->sctpt_sctp);
2647c478bd9Sstevel@tonic-gate 	} else if (state != SCTP_TB_IDLE) {
2657c478bd9Sstevel@tonic-gate 		ASSERT(state != SCTP_TB_TO_BE_FREED);
2667c478bd9Sstevel@tonic-gate 		sctp_tb->sctp_tb_state = SCTP_TB_TO_BE_FREED;
2677c478bd9Sstevel@tonic-gate 		/* sctp_timer_valid will free the mblk */
2687c478bd9Sstevel@tonic-gate 		return;
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 	freeb(mp);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate  * Called from sctp_timer(,,-1)
2757c478bd9Sstevel@tonic-gate  */
2767c478bd9Sstevel@tonic-gate void
2777c478bd9Sstevel@tonic-gate sctp_timer_stop(mblk_t *mp)
2787c478bd9Sstevel@tonic-gate {
2797c478bd9Sstevel@tonic-gate 	sctp_tb_t *sctp_tb;
2807c478bd9Sstevel@tonic-gate 	int state;
2817c478bd9Sstevel@tonic-gate 	sctpt_t *sctpt;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
2847c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_PCSIG);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	sctp_tb = (sctp_tb_t *)mp->b_datap->db_base;
2877c478bd9Sstevel@tonic-gate 	state = sctp_tb->sctp_tb_state;
2887c478bd9Sstevel@tonic-gate 
28945916cd2Sjpk 	dprint(5, ("sctp_timer_stop %p %d\n", (void *)mp, state));
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	if (state == SCTP_TB_RUNNING) {
2927c478bd9Sstevel@tonic-gate 		if (untimeout(sctp_tb->sctp_tb_tid) < 0) {
2937c478bd9Sstevel@tonic-gate 			sctp_tb->sctp_tb_state = SCTP_TB_CANCELLED;
2947c478bd9Sstevel@tonic-gate 		} else {
2957c478bd9Sstevel@tonic-gate 			sctp_tb->sctp_tb_state = SCTP_TB_IDLE;
2967c478bd9Sstevel@tonic-gate 			sctpt = (sctpt_t *)mp->b_rptr;
2977c478bd9Sstevel@tonic-gate 			SCTP_REFRELE(sctpt->sctpt_sctp);
2987c478bd9Sstevel@tonic-gate 		}
2997c478bd9Sstevel@tonic-gate 	} else if (state == SCTP_TB_RESCHED) {
3007c478bd9Sstevel@tonic-gate 		sctp_tb->sctp_tb_state = SCTP_TB_CANCELLED;
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate  * The user of the sctp_timer mechanism is required to call
3067c478bd9Sstevel@tonic-gate  * sctp_timer_valid() for each M_PCSIG message processed in the
3077c478bd9Sstevel@tonic-gate  * service procedures.
3087c478bd9Sstevel@tonic-gate  * sctp_timer_valid will return "true" if the timer actually did fire.
3097c478bd9Sstevel@tonic-gate  */
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate static boolean_t
3127c478bd9Sstevel@tonic-gate sctp_timer_valid(mblk_t *mp)
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate 	sctp_tb_t *sctp_tb;
3157c478bd9Sstevel@tonic-gate 	int state;
3167c478bd9Sstevel@tonic-gate 	sctpt_t *sctpt;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
3197c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_PCSIG);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	sctp_tb = (sctp_tb_t *)DB_BASE(mp);
3227c478bd9Sstevel@tonic-gate 	sctpt = (sctpt_t *)mp->b_rptr;
3237c478bd9Sstevel@tonic-gate 	state = sctp_tb->sctp_tb_state;
3247c478bd9Sstevel@tonic-gate 	if (state != SCTP_TB_RUNNING) {
3257c478bd9Sstevel@tonic-gate 		ASSERT(state != SCTP_TB_IDLE);
3267c478bd9Sstevel@tonic-gate 		if (state == SCTP_TB_TO_BE_FREED) {
3277c478bd9Sstevel@tonic-gate 			/*
3287c478bd9Sstevel@tonic-gate 			 * sctp_timer_free was called after the message
3297c478bd9Sstevel@tonic-gate 			 * was putq'ed.
3307c478bd9Sstevel@tonic-gate 			 */
3317c478bd9Sstevel@tonic-gate 			freeb(mp);
3327c478bd9Sstevel@tonic-gate 			return (B_FALSE);
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate 		if (state == SCTP_TB_CANCELLED) {
3357c478bd9Sstevel@tonic-gate 			/* The timer was stopped after the mblk was putq'ed */
3367c478bd9Sstevel@tonic-gate 			sctp_tb->sctp_tb_state = SCTP_TB_IDLE;
3377c478bd9Sstevel@tonic-gate 			return (B_FALSE);
3387c478bd9Sstevel@tonic-gate 		}
3397c478bd9Sstevel@tonic-gate 		if (state == SCTP_TB_RESCHED) {
3407c478bd9Sstevel@tonic-gate 			/*
3417c478bd9Sstevel@tonic-gate 			 * The timer was stopped and then restarted after
3427c478bd9Sstevel@tonic-gate 			 * the mblk was putq'ed.
3437c478bd9Sstevel@tonic-gate 			 * sctp_tb_time_left contains the number of ticks that
3447c478bd9Sstevel@tonic-gate 			 * the timer was restarted with.
3457c478bd9Sstevel@tonic-gate 			 * The sctp will not be disapper between the time
3467c478bd9Sstevel@tonic-gate 			 * the sctpt_t is marked SCTP_TB_RESCHED and when
3477c478bd9Sstevel@tonic-gate 			 * we get here as sctp_add_recvq() does a refhold.
3487c478bd9Sstevel@tonic-gate 			 */
3497c478bd9Sstevel@tonic-gate 			sctp_tb->sctp_tb_state = SCTP_TB_RUNNING;
3507c478bd9Sstevel@tonic-gate 			sctp_tb->sctp_tb_tid = timeout((pfv_t)sctp_timer_fire,
3517c478bd9Sstevel@tonic-gate 			    sctp_tb, sctp_tb->sctp_tb_time_left);
3527c478bd9Sstevel@tonic-gate 			SCTP_REFHOLD(sctpt->sctpt_sctp);
3537c478bd9Sstevel@tonic-gate 			return (B_FALSE);
3547c478bd9Sstevel@tonic-gate 		}
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 	sctp_tb->sctp_tb_state = SCTP_TB_IDLE;
3577c478bd9Sstevel@tonic-gate 	return (B_TRUE);
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate  * The SCTP timer call. Calls sctp_timer_valid() to verify whether
3627c478bd9Sstevel@tonic-gate  * timer was cancelled or not.
3637c478bd9Sstevel@tonic-gate  */
3647c478bd9Sstevel@tonic-gate void
3657c478bd9Sstevel@tonic-gate sctp_timer_call(sctp_t *sctp, mblk_t *mp)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	sctpt_t *sctpt = (sctpt_t *)mp->b_rptr;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	if (sctp_timer_valid(mp)) {
3707c478bd9Sstevel@tonic-gate 		(*sctpt->sctpt_pfv)(sctp, sctpt->sctpt_faddr);
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate /*
3757c478bd9Sstevel@tonic-gate  * Delayed ack
3767c478bd9Sstevel@tonic-gate  */
3777c478bd9Sstevel@tonic-gate void
3787c478bd9Sstevel@tonic-gate sctp_ack_timer(sctp_t *sctp)
3797c478bd9Sstevel@tonic-gate {
380f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
381f4b3ec61Sdh 
3827c478bd9Sstevel@tonic-gate 	sctp->sctp_ack_timer_running = 0;
383f4b3ec61Sdh 	sctp->sctp_sack_toggle = sctps->sctps_deferred_acks_max;
3845dd46ab5SKacheong Poon 	SCTPS_BUMP_MIB(sctps, sctpOutAckDelayed);
3857f093707Skcpoon 	(void) sctp_sack(sctp, NULL);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate  * Peer address heartbeat timer handler
3907c478bd9Sstevel@tonic-gate  */
3917c478bd9Sstevel@tonic-gate void
3927c478bd9Sstevel@tonic-gate sctp_heartbeat_timer(sctp_t *sctp)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	sctp_faddr_t	*fp;
3957c478bd9Sstevel@tonic-gate 	int64_t		now;
3967c478bd9Sstevel@tonic-gate 	int64_t		earliest_expiry;
3977c478bd9Sstevel@tonic-gate 	int		cnt;
398f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
3995dd46ab5SKacheong Poon 	int		pp_max_retr;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	if (sctp->sctp_strikes >= sctp->sctp_pa_max_rxt) {
4027c478bd9Sstevel@tonic-gate 		/*
4035dd46ab5SKacheong Poon 		 * If there is a peer address with no strikes, don't give up
4045dd46ab5SKacheong Poon 		 * yet unless we are under memory pressure.  If enough other
4055dd46ab5SKacheong Poon 		 * peer  address are down, we could otherwise fail the
4065dd46ab5SKacheong Poon 		 * association prematurely.  This is a byproduct of our
4075dd46ab5SKacheong Poon 		 * aggressive probe approach when a heartbeat fails to
4085dd46ab5SKacheong Poon 		 * connect. We may wish to revisit this...
4097c478bd9Sstevel@tonic-gate 		 */
4105dd46ab5SKacheong Poon 		if (sctps->sctps_reclaim || !sctp_is_a_faddr_clean(sctp)) {
4117c478bd9Sstevel@tonic-gate 			/* time to give up */
4125dd46ab5SKacheong Poon 			SCTPS_BUMP_MIB(sctps, sctpAborted);
4135dd46ab5SKacheong Poon 			SCTPS_BUMP_MIB(sctps, sctpTimHeartBeatDrop);
4147c478bd9Sstevel@tonic-gate 			sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL);
4157c478bd9Sstevel@tonic-gate 			sctp_clean_death(sctp, sctp->sctp_client_errno ?
4167c478bd9Sstevel@tonic-gate 			    sctp->sctp_client_errno : ETIMEDOUT);
4177c478bd9Sstevel@tonic-gate 			return;
4187c478bd9Sstevel@tonic-gate 		}
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	/* Only send heartbeats in the established state */
4227c478bd9Sstevel@tonic-gate 	if (sctp->sctp_state != SCTPS_ESTABLISHED) {
4237c478bd9Sstevel@tonic-gate 		dprint(5, ("sctp_heartbeat_timer: not in ESTABLISHED\n"));
4247c478bd9Sstevel@tonic-gate 		return;
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
427d3d50737SRafael Vanoni 	now = ddi_get_lbolt64();
4287c478bd9Sstevel@tonic-gate 	earliest_expiry = 0;
429f4b3ec61Sdh 	cnt = sctps->sctps_maxburst;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	/*
4327c478bd9Sstevel@tonic-gate 	 * Walk through all faddrs.  Since the timer should run infrequently
4337c478bd9Sstevel@tonic-gate 	 * and the number of peer addresses should not be big, this should
4347c478bd9Sstevel@tonic-gate 	 * be OK.
4357c478bd9Sstevel@tonic-gate 	 */
436*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
4375dd46ab5SKacheong Poon 		if (sctps->sctps_reclaim)
438*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			pp_max_retr = MIN(sctp_pp_early_abort, fp->sf_max_retr);
4395dd46ab5SKacheong Poon 		else
440*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			pp_max_retr = fp->sf_max_retr;
4415dd46ab5SKacheong Poon 
4427c478bd9Sstevel@tonic-gate 		/*
443c31292eeSkcpoon 		 * If the peer is unreachable because there is no available
444bd670b35SErik Nordmark 		 * source address, call sctp_get_dest() to see if it is
445c31292eeSkcpoon 		 * reachable now.  If it is OK, the state will become
446c31292eeSkcpoon 		 * unconfirmed.  And the following code to handle unconfirmed
447c31292eeSkcpoon 		 * address will be executed.  If it is still not OK,
448c31292eeSkcpoon 		 * re-schedule.  If heartbeat is enabled, only try this
449c31292eeSkcpoon 		 * up to the normal heartbeat max times.  But if heartbeat
450c31292eeSkcpoon 		 * is disable, this retry may go on forever.
4517c478bd9Sstevel@tonic-gate 		 */
452*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		if (fp->sf_state == SCTP_FADDRS_UNREACH) {
453bd670b35SErik Nordmark 			sctp_get_dest(sctp, fp);
454*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			if (fp->sf_state == SCTP_FADDRS_UNREACH) {
455*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				if (fp->sf_hb_enabled &&
456*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				    ++fp->sf_strikes > pp_max_retr &&
457c31292eeSkcpoon 				    sctp_faddr_dead(sctp, fp,
458c31292eeSkcpoon 				    SCTP_FADDRS_DOWN) == -1) {
459c31292eeSkcpoon 					/* Assoc is dead */
460c31292eeSkcpoon 					return;
461c31292eeSkcpoon 				}
462*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				fp->sf_hb_expiry = now + SET_HB_INTVL(fp);
463c31292eeSkcpoon 				goto set_expiry;
464c31292eeSkcpoon 			} else {
465c31292eeSkcpoon 				/* Send a heartbeat immediately. */
466*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				fp->sf_hb_expiry = now;
467c31292eeSkcpoon 			}
468c31292eeSkcpoon 		}
469c31292eeSkcpoon 		/*
470c31292eeSkcpoon 		 * Don't send heartbeat to this address if it is not
471c31292eeSkcpoon 		 * hb_enabled and the address has been confirmed.
472c31292eeSkcpoon 		 */
473*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		if (!fp->sf_hb_enabled && fp->sf_state !=
474*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		    SCTP_FADDRS_UNCONFIRMED) {
4757c478bd9Sstevel@tonic-gate 			continue;
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 		/*
4797c478bd9Sstevel@tonic-gate 		 * The heartbeat timer is expired.  If the address is dead,
4807c478bd9Sstevel@tonic-gate 		 * we still send heartbeat to it in case it becomes alive
481c31292eeSkcpoon 		 * again.  But we will only send once in a while, calculated
482c31292eeSkcpoon 		 * by SET_HB_INTVL().
4837c478bd9Sstevel@tonic-gate 		 *
4847c478bd9Sstevel@tonic-gate 		 * If the address is alive and there is a hearbeat pending,
4857c478bd9Sstevel@tonic-gate 		 * resend the heartbeat and start exponential backoff on the
4867c478bd9Sstevel@tonic-gate 		 * heartbeat timeout value.  If there is no heartbeat pending,
4877c478bd9Sstevel@tonic-gate 		 * just send out one.
4887c478bd9Sstevel@tonic-gate 		 */
489*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		if (now >= fp->sf_hb_expiry) {
490*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			if (fp->sf_hb_pending) {
4917c478bd9Sstevel@tonic-gate 				/*
4927c478bd9Sstevel@tonic-gate 				 * If an address is not confirmed, no need
4937c478bd9Sstevel@tonic-gate 				 * to bump the overall counter as it doesn't
4947c478bd9Sstevel@tonic-gate 				 * matter as we will not use it to send data
4957c478bd9Sstevel@tonic-gate 				 * and it should not affect the association.
4967c478bd9Sstevel@tonic-gate 				 */
497*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				switch (fp->sf_state) {
4987c478bd9Sstevel@tonic-gate 				case SCTP_FADDRS_ALIVE:
4997c478bd9Sstevel@tonic-gate 					sctp->sctp_strikes++;
5007c478bd9Sstevel@tonic-gate 					/* FALLTHRU */
5017c478bd9Sstevel@tonic-gate 				case SCTP_FADDRS_UNCONFIRMED:
5027c478bd9Sstevel@tonic-gate 					/*
5037c478bd9Sstevel@tonic-gate 					 * Retransmission implies that RTO
5047c478bd9Sstevel@tonic-gate 					 * is probably not correct.
5057c478bd9Sstevel@tonic-gate 					 */
506*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 					fp->sf_rtt_updates = 0;
507*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 					fp->sf_strikes++;
508*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 					if (fp->sf_strikes > pp_max_retr) {
5097c478bd9Sstevel@tonic-gate 						if (sctp_faddr_dead(sctp, fp,
5107c478bd9Sstevel@tonic-gate 						    SCTP_FADDRS_DOWN) == -1) {
5117c478bd9Sstevel@tonic-gate 							/* Assoc is dead */
5127c478bd9Sstevel@tonic-gate 							return;
5137c478bd9Sstevel@tonic-gate 						}
5147c478bd9Sstevel@tonic-gate 						/*
5157c478bd9Sstevel@tonic-gate 						 * Addr is down; keep initial
5167c478bd9Sstevel@tonic-gate 						 * RTO
5177c478bd9Sstevel@tonic-gate 						 */
518*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 						fp->sf_rto =
5197c478bd9Sstevel@tonic-gate 						    sctp->sctp_rto_initial;
5207c478bd9Sstevel@tonic-gate 						goto dead_addr;
5217c478bd9Sstevel@tonic-gate 					} else {
522fd7b5aedSGeorge Shepherd 						SCTP_CALC_RXT(sctp, fp,
523fd7b5aedSGeorge Shepherd 						    sctp->sctp_rto_max);
524*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 						fp->sf_hb_expiry = now +
525*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 						    fp->sf_rto;
5267c478bd9Sstevel@tonic-gate 					}
5277c478bd9Sstevel@tonic-gate 					break;
5287c478bd9Sstevel@tonic-gate 				case SCTP_FADDRS_DOWN:
5297c478bd9Sstevel@tonic-gate dead_addr:
530*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 					fp->sf_hb_expiry = now +
531*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 					    SET_HB_INTVL(fp);
5327c478bd9Sstevel@tonic-gate 					break;
5337c478bd9Sstevel@tonic-gate 				default:
5347c478bd9Sstevel@tonic-gate 					continue;
5357c478bd9Sstevel@tonic-gate 				}
5367c478bd9Sstevel@tonic-gate 			} else {
537c31292eeSkcpoon 				/*
538c31292eeSkcpoon 				 * If there is unack'ed data, no need to
539c31292eeSkcpoon 				 * send a heart beat.
540c31292eeSkcpoon 				 */
541*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 				if (fp->sf_suna > 0) {
542*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 					fp->sf_hb_expiry = now +
543*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 					    SET_HB_INTVL(fp);
544c31292eeSkcpoon 					goto set_expiry;
545c31292eeSkcpoon 				} else {
546*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 					fp->sf_hb_expiry = now + fp->sf_rto;
547c31292eeSkcpoon 				}
5487c478bd9Sstevel@tonic-gate 			}
5497c478bd9Sstevel@tonic-gate 			/*
5507c478bd9Sstevel@tonic-gate 			 * Note that the total number of heartbeat we can send
5517c478bd9Sstevel@tonic-gate 			 * out simultaneously is limited by sctp_maxburst.  If
5527c478bd9Sstevel@tonic-gate 			 * the limit is exceeded, we need to wait for the next
5537c478bd9Sstevel@tonic-gate 			 * timeout to send them.  This should only happen if
5547c478bd9Sstevel@tonic-gate 			 * there is unconfirmed address.  Note that hb_pending
5557c478bd9Sstevel@tonic-gate 			 * is set in sctp_send_heartbeat().  So if a heartbeat
5567c478bd9Sstevel@tonic-gate 			 * is not sent, it will not affect the state of the
5577c478bd9Sstevel@tonic-gate 			 * peer address.
5587c478bd9Sstevel@tonic-gate 			 */
559*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			if (fp->sf_state != SCTP_FADDRS_UNCONFIRMED ||
560*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			    cnt-- > 0)
5617c478bd9Sstevel@tonic-gate 				sctp_send_heartbeat(sctp, fp);
5627c478bd9Sstevel@tonic-gate 		}
563c31292eeSkcpoon set_expiry:
564*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		if (fp->sf_hb_expiry < earliest_expiry || earliest_expiry == 0)
565*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			earliest_expiry = fp->sf_hb_expiry;
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate 	if (sctp->sctp_autoclose != 0) {
5687c478bd9Sstevel@tonic-gate 		int64_t expire;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 		expire = sctp->sctp_active + sctp->sctp_autoclose;
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 		if (expire <= now) {
5737c478bd9Sstevel@tonic-gate 			dprint(3, ("sctp_heartbeat_timer: autoclosing\n"));
5747c478bd9Sstevel@tonic-gate 			sctp_send_shutdown(sctp, 0);
5757c478bd9Sstevel@tonic-gate 			return;
5767c478bd9Sstevel@tonic-gate 		}
5777c478bd9Sstevel@tonic-gate 		if (expire < earliest_expiry || earliest_expiry == 0)
5787c478bd9Sstevel@tonic-gate 			earliest_expiry = expire;
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	earliest_expiry -= now;
5827c478bd9Sstevel@tonic-gate 	if (earliest_expiry < 0)
5837c478bd9Sstevel@tonic-gate 		earliest_expiry = 1;
5847c478bd9Sstevel@tonic-gate 	sctp_timer(sctp, sctp->sctp_heartbeat_mp, earliest_expiry);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate void
5887c478bd9Sstevel@tonic-gate sctp_rexmit_timer(sctp_t *sctp, sctp_faddr_t *fp)
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate 	mblk_t 		*mp;
591fd7b5aedSGeorge Shepherd 	uint32_t	rto_max = sctp->sctp_rto_max;
592f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp->sctp_sctps;
5935dd46ab5SKacheong Poon 	int		pp_max_retr, pa_max_retr;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	ASSERT(fp != NULL);
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	dprint(3, ("sctp_timer: faddr=%x:%x:%x:%x\n",
598*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	    SCTP_PRINTADDR(fp->sf_faddr)));
5997c478bd9Sstevel@tonic-gate 
600*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	fp->sf_timer_running = 0;
6017c478bd9Sstevel@tonic-gate 
6025dd46ab5SKacheong Poon 	if (!sctps->sctps_reclaim) {
603*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		pp_max_retr = fp->sf_max_retr;
6045dd46ab5SKacheong Poon 		pa_max_retr = sctp->sctp_pa_max_rxt;
6055dd46ab5SKacheong Poon 	} else {
6065dd46ab5SKacheong Poon 		/* App may have set a very aggressive retransmission limit. */
607*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		pp_max_retr = MIN(sctp_pp_early_abort, fp->sf_max_retr);
6085dd46ab5SKacheong Poon 		pa_max_retr = MIN(sctp_pa_early_abort, sctp->sctp_pa_max_rxt);
6095dd46ab5SKacheong Poon 	}
6105dd46ab5SKacheong Poon 
6117c478bd9Sstevel@tonic-gate 	/* Check is we've reached the max for retries */
6127c478bd9Sstevel@tonic-gate 	if (sctp->sctp_state < SCTPS_ESTABLISHED) {
613*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		if (fp->sf_strikes >= sctp->sctp_max_init_rxt) {
6147c478bd9Sstevel@tonic-gate 			/* time to give up */
6155dd46ab5SKacheong Poon 			SCTPS_BUMP_MIB(sctps, sctpAborted);
6165dd46ab5SKacheong Poon 			SCTPS_BUMP_MIB(sctps, sctpTimRetransDrop);
6177c478bd9Sstevel@tonic-gate 			sctp_assoc_event(sctp, SCTP_CANT_STR_ASSOC, 0, NULL);
6187c478bd9Sstevel@tonic-gate 			sctp_clean_death(sctp, sctp->sctp_client_errno ?
6197c478bd9Sstevel@tonic-gate 			    sctp->sctp_client_errno : ETIMEDOUT);
6207c478bd9Sstevel@tonic-gate 			return;
6217c478bd9Sstevel@tonic-gate 		}
6227c478bd9Sstevel@tonic-gate 	} else if (sctp->sctp_state >= SCTPS_ESTABLISHED) {
6235dd46ab5SKacheong Poon 		if (sctp->sctp_strikes >= pa_max_retr) {
6247c478bd9Sstevel@tonic-gate 			/* time to give up */
6255dd46ab5SKacheong Poon 			SCTPS_BUMP_MIB(sctps, sctpAborted);
6265dd46ab5SKacheong Poon 			SCTPS_BUMP_MIB(sctps, sctpTimRetransDrop);
6277c478bd9Sstevel@tonic-gate 			sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL);
6287c478bd9Sstevel@tonic-gate 			sctp_clean_death(sctp, sctp->sctp_client_errno ?
6297c478bd9Sstevel@tonic-gate 			    sctp->sctp_client_errno : ETIMEDOUT);
6307c478bd9Sstevel@tonic-gate 			return;
6317c478bd9Sstevel@tonic-gate 		}
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate 
634*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	if (fp->sf_strikes >= pp_max_retr) {
6357c478bd9Sstevel@tonic-gate 		if (sctp_faddr_dead(sctp, fp, SCTP_FADDRS_DOWN) == -1) {
6367c478bd9Sstevel@tonic-gate 			return;
6377c478bd9Sstevel@tonic-gate 		}
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	switch (sctp->sctp_state) {
641c31292eeSkcpoon 	case SCTPS_SHUTDOWN_RECEIVED:
642c31292eeSkcpoon 		(void) sctp_shutdown_received(sctp, NULL, B_FALSE, B_TRUE,
643c31292eeSkcpoon 		    NULL);
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
646c31292eeSkcpoon 	case SCTPS_ESTABLISHED:
6477c478bd9Sstevel@tonic-gate 	case SCTPS_SHUTDOWN_PENDING:
6487c478bd9Sstevel@tonic-gate 		if (sctp->sctp_xmit_head == NULL &&
6497c478bd9Sstevel@tonic-gate 		    sctp->sctp_xmit_unsent == NULL) {
6507c478bd9Sstevel@tonic-gate 			/* Nothing to retransmit */
6517c478bd9Sstevel@tonic-gate 			if (sctp->sctp_state == SCTPS_SHUTDOWN_PENDING) {
6527c478bd9Sstevel@tonic-gate 				sctp_send_shutdown(sctp, 1);
6537c478bd9Sstevel@tonic-gate 			}
6547c478bd9Sstevel@tonic-gate 			return;
6557c478bd9Sstevel@tonic-gate 		}
6567c478bd9Sstevel@tonic-gate 
6575dd46ab5SKacheong Poon 		SCTPS_BUMP_MIB(sctps, sctpTimRetrans);
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 		sctp_rexmit(sctp, fp);
6607c478bd9Sstevel@tonic-gate 		/*
6617c478bd9Sstevel@tonic-gate 		 * sctp_rexmit() will increase the strikes and restart the
6627c478bd9Sstevel@tonic-gate 		 * timer, so return here.
6637c478bd9Sstevel@tonic-gate 		 */
6647c478bd9Sstevel@tonic-gate 		return;
6657c478bd9Sstevel@tonic-gate 	case SCTPS_COOKIE_WAIT:
6667c478bd9Sstevel@tonic-gate 		BUMP_LOCAL(sctp->sctp_T1expire);
6677c478bd9Sstevel@tonic-gate rxmit_init:
6687c478bd9Sstevel@tonic-gate 		/* retransmit init */
669f551bb10Svi 		/*
670f551bb10Svi 		 * We don't take the conn hash lock here since the source
671f551bb10Svi 		 * address list won't be modified (it would have been done
672f551bb10Svi 		 * the first time around).
673f551bb10Svi 		 */
674bd670b35SErik Nordmark 		mp = sctp_init_mp(sctp, fp);
6757c478bd9Sstevel@tonic-gate 		if (mp != NULL) {
6765dd46ab5SKacheong Poon 			SCTPS_BUMP_MIB(sctps, sctpTimRetrans);
677*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			(void) conn_ip_output(mp, fp->sf_ixa);
678bd670b35SErik Nordmark 			BUMP_LOCAL(sctp->sctp_opkts);
6797c478bd9Sstevel@tonic-gate 		}
680fd7b5aedSGeorge Shepherd 		rto_max = sctp->sctp_rto_max_init;
6817c478bd9Sstevel@tonic-gate 		break;
682bd670b35SErik Nordmark 	case SCTPS_COOKIE_ECHOED:
6837c478bd9Sstevel@tonic-gate 		BUMP_LOCAL(sctp->sctp_T1expire);
6847c478bd9Sstevel@tonic-gate 		if (sctp->sctp_cookie_mp == NULL) {
6857c478bd9Sstevel@tonic-gate 			sctp->sctp_state = SCTPS_COOKIE_WAIT;
6867c478bd9Sstevel@tonic-gate 			goto rxmit_init;
6877c478bd9Sstevel@tonic-gate 		}
6887c478bd9Sstevel@tonic-gate 		mp = dupmsg(sctp->sctp_cookie_mp);
6897c478bd9Sstevel@tonic-gate 		if (mp == NULL)
6907c478bd9Sstevel@tonic-gate 			break;
691*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		(void) conn_ip_output(mp, fp->sf_ixa);
692bd670b35SErik Nordmark 		BUMP_LOCAL(sctp->sctp_opkts);
6935dd46ab5SKacheong Poon 		SCTPS_BUMP_MIB(sctps, sctpTimRetrans);
694fd7b5aedSGeorge Shepherd 		rto_max = sctp->sctp_rto_max_init;
6957c478bd9Sstevel@tonic-gate 		break;
6967c478bd9Sstevel@tonic-gate 	case SCTPS_SHUTDOWN_SENT:
6977c478bd9Sstevel@tonic-gate 		BUMP_LOCAL(sctp->sctp_T2expire);
6987c478bd9Sstevel@tonic-gate 		sctp_send_shutdown(sctp, 1);
6995dd46ab5SKacheong Poon 		SCTPS_BUMP_MIB(sctps, sctpTimRetrans);
7007c478bd9Sstevel@tonic-gate 		break;
7017c478bd9Sstevel@tonic-gate 	case SCTPS_SHUTDOWN_ACK_SENT:
7027c478bd9Sstevel@tonic-gate 		/* We shouldn't have any more outstanding data */
7037c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_xmit_head == NULL);
7047c478bd9Sstevel@tonic-gate 		ASSERT(sctp->sctp_xmit_unsent == NULL);
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 		BUMP_LOCAL(sctp->sctp_T2expire);
70777c67f2fSkcpoon 		(void) sctp_shutdown_received(sctp, NULL, B_FALSE, B_TRUE,
70877c67f2fSkcpoon 		    NULL);
7095dd46ab5SKacheong Poon 		SCTPS_BUMP_MIB(sctps, sctpTimRetrans);
7107c478bd9Sstevel@tonic-gate 		break;
7117c478bd9Sstevel@tonic-gate 	default:
7127c478bd9Sstevel@tonic-gate 		ASSERT(0);
7137c478bd9Sstevel@tonic-gate 		break;
7147c478bd9Sstevel@tonic-gate 	}
7157c478bd9Sstevel@tonic-gate 
716*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	fp->sf_strikes++;
7177c478bd9Sstevel@tonic-gate 	sctp->sctp_strikes++;
718fd7b5aedSGeorge Shepherd 	SCTP_CALC_RXT(sctp, fp, rto_max);
7197c478bd9Sstevel@tonic-gate 
720*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto);
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate /*
7247c478bd9Sstevel@tonic-gate  * RTO calculation. timesent and now are both in ms.
7257c478bd9Sstevel@tonic-gate  */
7267c478bd9Sstevel@tonic-gate void
7277c478bd9Sstevel@tonic-gate sctp_update_rtt(sctp_t *sctp, sctp_faddr_t *fp, clock_t delta)
7287c478bd9Sstevel@tonic-gate {
7297c478bd9Sstevel@tonic-gate 	int rtt;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	/* Calculate the RTT in ms */
7327c478bd9Sstevel@tonic-gate 	rtt = (int)delta;
7337c478bd9Sstevel@tonic-gate 	rtt = rtt > 0 ? rtt : 1;
7347c478bd9Sstevel@tonic-gate 
73545916cd2Sjpk 	dprint(5, ("sctp_update_rtt: fp = %p, rtt = %d\n", (void *)fp, rtt));
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	/* Is this the first RTT measurement? */
738*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	if (fp->sf_srtt == -1) {
739*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		fp->sf_srtt = rtt;
740*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		fp->sf_rttvar = rtt / 2;
741*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		fp->sf_rto = 3 * rtt; /* == rtt + 4 * rttvar ( == rtt / 2) */
7427c478bd9Sstevel@tonic-gate 	} else {
7437c478bd9Sstevel@tonic-gate 		int abs;
7447c478bd9Sstevel@tonic-gate 		/*
7457c478bd9Sstevel@tonic-gate 		 * Versions of the RTO equations that use fixed-point math.
7467c478bd9Sstevel@tonic-gate 		 * alpha and beta are NOT tunable in this implementation,
7477c478bd9Sstevel@tonic-gate 		 * and so are hard-coded in. alpha = 1/8, beta = 1/4.
7487c478bd9Sstevel@tonic-gate 		 */
749*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		abs = fp->sf_srtt - rtt;
7507c478bd9Sstevel@tonic-gate 		abs = abs >= 0 ? abs : -abs;
751*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		fp->sf_rttvar = (3 * fp->sf_rttvar + abs) >> 2;
752*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		fp->sf_rttvar = fp->sf_rttvar != 0 ? fp->sf_rttvar : 1;
7537c478bd9Sstevel@tonic-gate 
754*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		fp->sf_srtt = (7 * fp->sf_srtt + rtt) >> 3;
755*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		fp->sf_rto = fp->sf_srtt + 4 * fp->sf_rttvar;
7567c478bd9Sstevel@tonic-gate 	}
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	dprint(5, ("sctp_update_rtt: srtt = %d, rttvar = %d, rto = %d\n",
759*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	    fp->sf_srtt, fp->sf_rttvar, fp->sf_rto));
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	/* Bound the RTO by configured min and max values */
762*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	if (fp->sf_rto < sctp->sctp_rto_min) {
763*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		fp->sf_rto = sctp->sctp_rto_min;
7647c478bd9Sstevel@tonic-gate 	}
765*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	if (fp->sf_rto > sctp->sctp_rto_max) {
766*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		fp->sf_rto = sctp->sctp_rto_max;
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 
7699f13099eSGeorge Shepherd 	SCTP_MAX_RTO(sctp, fp);
770*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	fp->sf_rtt_updates++;
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate void
7747c478bd9Sstevel@tonic-gate sctp_free_faddr_timers(sctp_t *sctp)
7757c478bd9Sstevel@tonic-gate {
7767c478bd9Sstevel@tonic-gate 	sctp_faddr_t *fp;
7777c478bd9Sstevel@tonic-gate 
778*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
779*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		if (fp->sf_timer_mp != NULL) {
780*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			sctp_timer_free(fp->sf_timer_mp);
781*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			fp->sf_timer_mp = NULL;
782*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			fp->sf_timer_running = 0;
7837c478bd9Sstevel@tonic-gate 		}
784*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		if (fp->sf_rc_timer_mp != NULL) {
785*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			sctp_timer_free(fp->sf_rc_timer_mp);
786*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			fp->sf_rc_timer_mp = NULL;
787*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 			fp->sf_rc_timer_running = 0;
7887c478bd9Sstevel@tonic-gate 		}
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate void
7937c478bd9Sstevel@tonic-gate sctp_stop_faddr_timers(sctp_t *sctp)
7947c478bd9Sstevel@tonic-gate {
7957c478bd9Sstevel@tonic-gate 	sctp_faddr_t *fp;
7967c478bd9Sstevel@tonic-gate 
797*6be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
7987c478bd9Sstevel@tonic-gate 		SCTP_FADDR_TIMER_STOP(fp);
7997c478bd9Sstevel@tonic-gate 		SCTP_FADDR_RC_TIMER_STOP(fp);
8007c478bd9Sstevel@tonic-gate 	}
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate void
8047c478bd9Sstevel@tonic-gate sctp_process_timer(sctp_t *sctp)
8057c478bd9Sstevel@tonic-gate {
8067c478bd9Sstevel@tonic-gate 	mblk_t *mp;
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	ASSERT(sctp->sctp_running);
8097c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&sctp->sctp_lock));
8107c478bd9Sstevel@tonic-gate 	while ((mp = sctp->sctp_timer_mp) != NULL) {
8117c478bd9Sstevel@tonic-gate 		ASSERT(DB_TYPE(mp) == M_PCSIG);
8127c478bd9Sstevel@tonic-gate 		/*
8137c478bd9Sstevel@tonic-gate 		 * Since the timer mblk can be freed in sctp_timer_call(),
8147c478bd9Sstevel@tonic-gate 		 * we need to grab the b_cont before that.
8157c478bd9Sstevel@tonic-gate 		 */
8167c478bd9Sstevel@tonic-gate 		sctp->sctp_timer_mp = mp->b_cont;
8177c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
818fb9c4d48SGeorge Shepherd 		/*
819fb9c4d48SGeorge Shepherd 		 * We have a reference on the sctp, the lock must be
820fb9c4d48SGeorge Shepherd 		 * dropped to avoid deadlocks with functions potentially
821fb9c4d48SGeorge Shepherd 		 * called in this context which in turn call untimeout().
822fb9c4d48SGeorge Shepherd 		 */
823fb9c4d48SGeorge Shepherd 		mutex_exit(&sctp->sctp_lock);
8247c478bd9Sstevel@tonic-gate 		sctp_timer_call(sctp, mp);
825fb9c4d48SGeorge Shepherd 		mutex_enter(&sctp->sctp_lock);
8267c478bd9Sstevel@tonic-gate 	}
8277c478bd9Sstevel@tonic-gate 	SCTP_REFRELE(sctp);
8287c478bd9Sstevel@tonic-gate }
829