root/usr/src/uts/common/inet/sctp/sctp_timer.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#include <sys/types.h>
#include <sys/systm.h>
#include <sys/stream.h>
#include <sys/cmn_err.h>
#include <sys/strsubr.h>
#include <sys/strsun.h>

#include <netinet/in.h>
#include <netinet/ip6.h>

#include <inet/common.h>
#include <inet/ip.h>
#include <inet/mib2.h>
#include <inet/ipclassifier.h>
#include "sctp_impl.h"
#include "sctp_asconf.h"

/* Timer block states. */
typedef enum {
        SCTP_TB_RUNNING = 1,
        SCTP_TB_IDLE,
/* Could not stop/free before mblk got queued */
        SCTP_TB_RESCHED,        /* sctp_tb_time_left contains tick count */
        SCTP_TB_CANCELLED,
        SCTP_TB_TO_BE_FREED
} timer_block_state;

typedef struct sctp_tb_s {
        timer_block_state       sctp_tb_state;
        timeout_id_t            sctp_tb_tid;
        mblk_t                  *sctp_tb_mp;
        clock_t                 sctp_tb_time_left;
} sctp_tb_t;

/*
 * Early abort threshold when the system is under pressure, sctps_reclaim
 * is on.
 *
 * sctp_pa_early_abort: number of strikes per association before abort
 * sctp_pp_early_abort: number of strikes per peer address before abort
 */
uint32_t sctp_pa_early_abort = 5;
uint32_t sctp_pp_early_abort = 3;

static void sctp_timer_fire(sctp_tb_t *);

/*
 *              sctp_timer mechanism.
 *
 * Each timer is represented by a timer mblk. When the
 * timer fires, and the sctp_t is busy, the timer mblk will be put on
 * the associated sctp_t timer queue so that it can be executed when
 * the thread holding the lock on the sctp_t is done with its job.
 *
 * Note that there is no lock to protect the timer mblk state.  The reason
 * is that the timer state can only be changed by a thread holding the
 * lock on the sctp_t.
 *
 * The interface consists of 4 entry points:
 *      sctp_timer_alloc        - create a timer mblk
 *      sctp_timer_free         - free a timer mblk
 *      sctp_timer              - start, restart, stop the timer
 *      sctp_timer_valid        - called by sctp_process_recvq to verify that
 *                                the timer did indeed fire.
 */


/*
 * Start, restart, stop the timer.
 * If "tim" is -1 the timer is stopped.
 * Otherwise, the timer is stopped if it is already running, and
 * set to fire tim clock ticks from now.
 */
void
sctp_timer(sctp_t *sctp, mblk_t *mp, clock_t tim)
{
        sctp_tb_t *sctp_tb;
        int state;

        ASSERT(sctp != NULL && mp != NULL);
        ASSERT((mp->b_rptr - mp->b_datap->db_base) == sizeof (sctp_tb_t));
        ASSERT(mp->b_datap->db_type == M_PCSIG);

        sctp_tb = (sctp_tb_t *)mp->b_datap->db_base;
        if (tim >= 0) {
                state = sctp_tb->sctp_tb_state;
                sctp_tb->sctp_tb_time_left = tim;
                if (state == SCTP_TB_RUNNING) {
                        if (untimeout(sctp_tb->sctp_tb_tid) < 0) {
                                sctp_tb->sctp_tb_state = SCTP_TB_RESCHED;
                                /* sctp_timer_valid will start timer */
                                return;
                        }
                } else if (state != SCTP_TB_IDLE) {
                        ASSERT(state != SCTP_TB_TO_BE_FREED);
                        if (state == SCTP_TB_CANCELLED) {
                                sctp_tb->sctp_tb_state = SCTP_TB_RESCHED;
                                /* sctp_timer_valid will start timer */
                                return;
                        }
                        if (state == SCTP_TB_RESCHED) {
                                /* sctp_timer_valid will start timer */
                                return;
                        }
                } else {
                        SCTP_REFHOLD(sctp);
                }
                sctp_tb->sctp_tb_state = SCTP_TB_RUNNING;
                sctp_tb->sctp_tb_tid =
                    timeout((pfv_t)sctp_timer_fire, sctp_tb, tim);
                return;
        }
        switch (tim) {
        case -1:
                sctp_timer_stop(mp);
                break;
        default:
                ASSERT(0);
                break;
        }
}

/*
 * sctp_timer_alloc is called by sctp_init to allocate and initialize a
 * sctp timer.
 *
 * Allocate an M_PCSIG timer message. The space between db_base and
 * b_rptr is used by the sctp_timer mechanism, and after b_rptr there is
 * space for sctpt_t.
 */
mblk_t *
sctp_timer_alloc(sctp_t *sctp, pfv_t func, int sleep)
{
        mblk_t *mp;
        sctp_tb_t *sctp_tb;
        sctpt_t *sctpt;
        sctp_stack_t    *sctps = sctp->sctp_sctps;

        if (sleep == KM_SLEEP) {
                mp = allocb_wait(sizeof (sctp_t) + sizeof (sctp_tb_t), BPRI_HI,
                    STR_NOSIG, NULL);
        } else {
                mp = allocb(sizeof (sctp_t) + sizeof (sctp_tb_t), BPRI_HI);
        }
        if (mp != NULL) {
                mp->b_datap->db_type = M_PCSIG;
                sctp_tb = (sctp_tb_t *)mp->b_datap->db_base;
                mp->b_rptr = (uchar_t *)&sctp_tb[1];
                mp->b_wptr = mp->b_rptr + sizeof (sctpt_t);
                sctp_tb->sctp_tb_state = SCTP_TB_IDLE;
                sctp_tb->sctp_tb_mp = mp;

                sctpt = (sctpt_t *)mp->b_rptr;
                sctpt->sctpt_sctp = sctp;
                sctpt->sctpt_faddr = NULL;      /* set when starting timer */
                sctpt->sctpt_pfv = func;
                return (mp);
        }
        SCTP_KSTAT(sctps, sctp_add_timer);
        return (NULL);
}

/*
 * timeout() callback function.
 * Put the message on the process control block's queue.
 * If the timer is stopped or freed after
 * it has fired then sctp_timer() and sctp_timer_valid() will clean
 * things up.
 */
static void
sctp_timer_fire(sctp_tb_t *sctp_tb)
{
        mblk_t *mp;
        sctp_t *sctp;
        sctpt_t *sctpt;

        mp = sctp_tb->sctp_tb_mp;
        ASSERT(sctp_tb == (sctp_tb_t *)mp->b_datap->db_base);
        ASSERT(mp->b_datap->db_type == M_PCSIG);

        sctpt = (sctpt_t *)mp->b_rptr;
        sctp = sctpt->sctpt_sctp;
        ASSERT(sctp != NULL);

        mutex_enter(&sctp->sctp_lock);
        if (sctp->sctp_running) {
                /*
                 * Put the timer mblk to the special sctp_timer_mp list.
                 * This timer will be handled when the thread using this
                 * SCTP is done with its job.
                 */
                if (sctp->sctp_timer_mp == NULL) {
                        SCTP_REFHOLD(sctp);
                        sctp->sctp_timer_mp = mp;
                } else {
                        linkb(sctp->sctp_timer_mp, mp);
                }
                mp->b_cont = NULL;
                mutex_exit(&sctp->sctp_lock);
        } else {
                sctp->sctp_running = B_TRUE;
                mutex_exit(&sctp->sctp_lock);

                sctp_timer_call(sctp, mp);
                WAKE_SCTP(sctp);
        }
        SCTP_REFRELE(sctp);
}

/*
 * Logically free a timer mblk (that might have a pending timeout().)
 * If the timer has fired and the mblk has been put on the queue then
 * sctp_timer_valid will free the mblk.
 */
void
sctp_timer_free(mblk_t *mp)
{
        sctp_tb_t *sctp_tb;
        int state;
        sctpt_t *sctpt;

        ASSERT(mp != NULL);
        ASSERT((mp->b_rptr - mp->b_datap->db_base) == sizeof (sctp_tb_t));
        ASSERT(mp->b_datap->db_type == M_PCSIG);

        sctp_tb = (sctp_tb_t *)mp->b_datap->db_base;
        state = sctp_tb->sctp_tb_state;

        dprint(5, ("sctp_timer_free %p state %d\n", (void *)mp, state));

        if (state == SCTP_TB_RUNNING) {
                if (untimeout(sctp_tb->sctp_tb_tid) < 0) {
                        sctp_tb->sctp_tb_state = SCTP_TB_TO_BE_FREED;
                        /* sctp_timer_valid will free the mblk */
                        return;
                }
                sctpt = (sctpt_t *)mp->b_rptr;
                SCTP_REFRELE(sctpt->sctpt_sctp);
        } else if (state != SCTP_TB_IDLE) {
                ASSERT(state != SCTP_TB_TO_BE_FREED);
                sctp_tb->sctp_tb_state = SCTP_TB_TO_BE_FREED;
                /* sctp_timer_valid will free the mblk */
                return;
        }
        freeb(mp);
}

/*
 * Called from sctp_timer(,,-1)
 */
void
sctp_timer_stop(mblk_t *mp)
{
        sctp_tb_t *sctp_tb;
        int state;
        sctpt_t *sctpt;

        ASSERT(mp != NULL);
        ASSERT(mp->b_datap->db_type == M_PCSIG);

        sctp_tb = (sctp_tb_t *)mp->b_datap->db_base;
        state = sctp_tb->sctp_tb_state;

        dprint(5, ("sctp_timer_stop %p %d\n", (void *)mp, state));

        if (state == SCTP_TB_RUNNING) {
                if (untimeout(sctp_tb->sctp_tb_tid) < 0) {
                        sctp_tb->sctp_tb_state = SCTP_TB_CANCELLED;
                } else {
                        sctp_tb->sctp_tb_state = SCTP_TB_IDLE;
                        sctpt = (sctpt_t *)mp->b_rptr;
                        SCTP_REFRELE(sctpt->sctpt_sctp);
                }
        } else if (state == SCTP_TB_RESCHED) {
                sctp_tb->sctp_tb_state = SCTP_TB_CANCELLED;
        }
}

/*
 * The user of the sctp_timer mechanism is required to call
 * sctp_timer_valid() for each M_PCSIG message processed in the
 * service procedures.
 * sctp_timer_valid will return "true" if the timer actually did fire.
 */

static boolean_t
sctp_timer_valid(mblk_t *mp)
{
        sctp_tb_t *sctp_tb;
        int state;
        sctpt_t *sctpt;

        ASSERT(mp != NULL);
        ASSERT(mp->b_datap->db_type == M_PCSIG);

        sctp_tb = (sctp_tb_t *)DB_BASE(mp);
        sctpt = (sctpt_t *)mp->b_rptr;
        state = sctp_tb->sctp_tb_state;
        if (state != SCTP_TB_RUNNING) {
                ASSERT(state != SCTP_TB_IDLE);
                if (state == SCTP_TB_TO_BE_FREED) {
                        /*
                         * sctp_timer_free was called after the message
                         * was putq'ed.
                         */
                        freeb(mp);
                        return (B_FALSE);
                }
                if (state == SCTP_TB_CANCELLED) {
                        /* The timer was stopped after the mblk was putq'ed */
                        sctp_tb->sctp_tb_state = SCTP_TB_IDLE;
                        return (B_FALSE);
                }
                if (state == SCTP_TB_RESCHED) {
                        /*
                         * The timer was stopped and then restarted after
                         * the mblk was putq'ed.
                         * sctp_tb_time_left contains the number of ticks that
                         * the timer was restarted with.
                         * The sctp will not be disapper between the time
                         * the sctpt_t is marked SCTP_TB_RESCHED and when
                         * we get here as sctp_add_recvq() does a refhold.
                         */
                        sctp_tb->sctp_tb_state = SCTP_TB_RUNNING;
                        sctp_tb->sctp_tb_tid = timeout((pfv_t)sctp_timer_fire,
                            sctp_tb, sctp_tb->sctp_tb_time_left);
                        SCTP_REFHOLD(sctpt->sctpt_sctp);
                        return (B_FALSE);
                }
        }
        sctp_tb->sctp_tb_state = SCTP_TB_IDLE;
        return (B_TRUE);
}

/*
 * The SCTP timer call. Calls sctp_timer_valid() to verify whether
 * timer was cancelled or not.
 */
void
sctp_timer_call(sctp_t *sctp, mblk_t *mp)
{
        sctpt_t *sctpt = (sctpt_t *)mp->b_rptr;

        if (sctp_timer_valid(mp)) {
                (*sctpt->sctpt_pfv)(sctp, sctpt->sctpt_faddr);
        }
}

/*
 * Delayed ack
 */
void
sctp_ack_timer(sctp_t *sctp)
{
        sctp_stack_t    *sctps = sctp->sctp_sctps;

        sctp->sctp_ack_timer_running = 0;
        sctp->sctp_sack_toggle = sctps->sctps_deferred_acks_max;
        SCTPS_BUMP_MIB(sctps, sctpOutAckDelayed);
        (void) sctp_sack(sctp, NULL);
}

/*
 * Peer address heartbeat timer handler
 */
void
sctp_heartbeat_timer(sctp_t *sctp)
{
        sctp_faddr_t    *fp;
        int64_t         now;
        int64_t         earliest_expiry;
        int             cnt;
        sctp_stack_t    *sctps = sctp->sctp_sctps;
        int             pp_max_retr;

        if (sctp->sctp_strikes >= sctp->sctp_pa_max_rxt) {
                /*
                 * If there is a peer address with no strikes, don't give up
                 * yet unless we are under memory pressure.  If enough other
                 * peer  address are down, we could otherwise fail the
                 * association prematurely.  This is a byproduct of our
                 * aggressive probe approach when a heartbeat fails to
                 * connect. We may wish to revisit this...
                 */
                if (sctps->sctps_reclaim || !sctp_is_a_faddr_clean(sctp)) {
                        /* time to give up */
                        SCTPS_BUMP_MIB(sctps, sctpAborted);
                        SCTPS_BUMP_MIB(sctps, sctpTimHeartBeatDrop);
                        sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL);
                        sctp_clean_death(sctp, sctp->sctp_client_errno ?
                            sctp->sctp_client_errno : ETIMEDOUT);
                        return;
                }
        }

        /* Only send heartbeats in the established state */
        if (sctp->sctp_state != SCTPS_ESTABLISHED) {
                dprint(5, ("sctp_heartbeat_timer: not in ESTABLISHED\n"));
                return;
        }

        now = ddi_get_lbolt64();
        earliest_expiry = 0;
        cnt = sctps->sctps_maxburst;

        /*
         * Walk through all faddrs.  Since the timer should run infrequently
         * and the number of peer addresses should not be big, this should
         * be OK.
         */
        for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
                if (sctps->sctps_reclaim)
                        pp_max_retr = MIN(sctp_pp_early_abort, fp->sf_max_retr);
                else
                        pp_max_retr = fp->sf_max_retr;

                /*
                 * If the peer is unreachable because there is no available
                 * source address, call sctp_get_dest() to see if it is
                 * reachable now.  If it is OK, the state will become
                 * unconfirmed.  And the following code to handle unconfirmed
                 * address will be executed.  If it is still not OK,
                 * re-schedule.  If heartbeat is enabled, only try this
                 * up to the normal heartbeat max times.  But if heartbeat
                 * is disable, this retry may go on forever.
                 */
                if (fp->sf_state == SCTP_FADDRS_UNREACH) {
                        sctp_get_dest(sctp, fp);
                        if (fp->sf_state == SCTP_FADDRS_UNREACH) {
                                if (fp->sf_hb_enabled &&
                                    ++fp->sf_strikes > pp_max_retr &&
                                    sctp_faddr_dead(sctp, fp,
                                    SCTP_FADDRS_DOWN) == -1) {
                                        /* Assoc is dead */
                                        return;
                                }
                                fp->sf_hb_expiry = now + SET_HB_INTVL(fp);
                                goto set_expiry;
                        } else {
                                /* Send a heartbeat immediately. */
                                fp->sf_hb_expiry = now;
                        }
                }
                /*
                 * Don't send heartbeat to this address if it is not
                 * hb_enabled and the address has been confirmed.
                 */
                if (!fp->sf_hb_enabled && fp->sf_state !=
                    SCTP_FADDRS_UNCONFIRMED) {
                        continue;
                }

                /*
                 * The heartbeat timer is expired.  If the address is dead,
                 * we still send heartbeat to it in case it becomes alive
                 * again.  But we will only send once in a while, calculated
                 * by SET_HB_INTVL().
                 *
                 * If the address is alive and there is a hearbeat pending,
                 * resend the heartbeat and start exponential backoff on the
                 * heartbeat timeout value.  If there is no heartbeat pending,
                 * just send out one.
                 */
                if (now >= fp->sf_hb_expiry) {
                        if (fp->sf_hb_pending) {
                                /*
                                 * If an address is not confirmed, no need
                                 * to bump the overall counter as it doesn't
                                 * matter as we will not use it to send data
                                 * and it should not affect the association.
                                 */
                                switch (fp->sf_state) {
                                case SCTP_FADDRS_ALIVE:
                                        sctp->sctp_strikes++;
                                        /* FALLTHRU */
                                case SCTP_FADDRS_UNCONFIRMED:
                                        /*
                                         * Retransmission implies that RTO
                                         * is probably not correct.
                                         */
                                        fp->sf_rtt_updates = 0;
                                        fp->sf_strikes++;
                                        if (fp->sf_strikes > pp_max_retr) {
                                                if (sctp_faddr_dead(sctp, fp,
                                                    SCTP_FADDRS_DOWN) == -1) {
                                                        /* Assoc is dead */
                                                        return;
                                                }
                                                /*
                                                 * Addr is down; keep initial
                                                 * RTO
                                                 */
                                                fp->sf_rto =
                                                    sctp->sctp_rto_initial;
                                                goto dead_addr;
                                        } else {
                                                SCTP_CALC_RXT(sctp, fp,
                                                    sctp->sctp_rto_max);
                                                fp->sf_hb_expiry = now +
                                                    fp->sf_rto;
                                        }
                                        break;
                                case SCTP_FADDRS_DOWN:
dead_addr:
                                        fp->sf_hb_expiry = now +
                                            SET_HB_INTVL(fp);
                                        break;
                                default:
                                        continue;
                                }
                        } else {
                                /*
                                 * If there is unack'ed data, no need to
                                 * send a heart beat.
                                 */
                                if (fp->sf_suna > 0) {
                                        fp->sf_hb_expiry = now +
                                            SET_HB_INTVL(fp);
                                        goto set_expiry;
                                } else {
                                        fp->sf_hb_expiry = now + fp->sf_rto;
                                }
                        }
                        /*
                         * Note that the total number of heartbeat we can send
                         * out simultaneously is limited by sctp_maxburst.  If
                         * the limit is exceeded, we need to wait for the next
                         * timeout to send them.  This should only happen if
                         * there is unconfirmed address.  Note that hb_pending
                         * is set in sctp_send_heartbeat().  So if a heartbeat
                         * is not sent, it will not affect the state of the
                         * peer address.
                         */
                        if (fp->sf_state != SCTP_FADDRS_UNCONFIRMED ||
                            cnt-- > 0)
                                sctp_send_heartbeat(sctp, fp);
                }
set_expiry:
                if (fp->sf_hb_expiry < earliest_expiry || earliest_expiry == 0)
                        earliest_expiry = fp->sf_hb_expiry;
        }
        if (sctp->sctp_autoclose != 0) {
                int64_t expire;

                expire = sctp->sctp_active + sctp->sctp_autoclose;

                if (expire <= now) {
                        dprint(3, ("sctp_heartbeat_timer: autoclosing\n"));
                        sctp_send_shutdown(sctp, 0);
                        return;
                }
                if (expire < earliest_expiry || earliest_expiry == 0)
                        earliest_expiry = expire;
        }

        earliest_expiry -= now;
        if (earliest_expiry < 0)
                earliest_expiry = 1;
        sctp_timer(sctp, sctp->sctp_heartbeat_mp, earliest_expiry);
}

void
sctp_rexmit_timer(sctp_t *sctp, sctp_faddr_t *fp)
{
        mblk_t          *mp;
        uint32_t        rto_max = sctp->sctp_rto_max;
        sctp_stack_t    *sctps = sctp->sctp_sctps;
        int             pp_max_retr, pa_max_retr;

        ASSERT(fp != NULL);

        dprint(3, ("sctp_timer: faddr=%x:%x:%x:%x\n",
            SCTP_PRINTADDR(fp->sf_faddr)));

        fp->sf_timer_running = 0;

        if (!sctps->sctps_reclaim) {
                pp_max_retr = fp->sf_max_retr;
                pa_max_retr = sctp->sctp_pa_max_rxt;
        } else {
                /* App may have set a very aggressive retransmission limit. */
                pp_max_retr = MIN(sctp_pp_early_abort, fp->sf_max_retr);
                pa_max_retr = MIN(sctp_pa_early_abort, sctp->sctp_pa_max_rxt);
        }

        /* Check is we've reached the max for retries */
        if (sctp->sctp_state < SCTPS_ESTABLISHED) {
                if (fp->sf_strikes >= sctp->sctp_max_init_rxt) {
                        /* time to give up */
                        SCTPS_BUMP_MIB(sctps, sctpAborted);
                        SCTPS_BUMP_MIB(sctps, sctpTimRetransDrop);
                        sctp_assoc_event(sctp, SCTP_CANT_STR_ASSOC, 0, NULL);
                        sctp_clean_death(sctp, sctp->sctp_client_errno ?
                            sctp->sctp_client_errno : ETIMEDOUT);
                        return;
                }
        } else if (sctp->sctp_state >= SCTPS_ESTABLISHED) {
                if (sctp->sctp_strikes >= pa_max_retr) {
                        /* time to give up */
                        SCTPS_BUMP_MIB(sctps, sctpAborted);
                        SCTPS_BUMP_MIB(sctps, sctpTimRetransDrop);
                        sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL);
                        sctp_clean_death(sctp, sctp->sctp_client_errno ?
                            sctp->sctp_client_errno : ETIMEDOUT);
                        return;
                }
        }

        if (fp->sf_strikes >= pp_max_retr) {
                if (sctp_faddr_dead(sctp, fp, SCTP_FADDRS_DOWN) == -1) {
                        return;
                }
        }

        switch (sctp->sctp_state) {
        case SCTPS_SHUTDOWN_RECEIVED:
                (void) sctp_shutdown_received(sctp, NULL, B_FALSE, B_TRUE,
                    NULL);

                /* FALLTHRU */
        case SCTPS_ESTABLISHED:
        case SCTPS_SHUTDOWN_PENDING:
                if (sctp->sctp_xmit_head == NULL &&
                    sctp->sctp_xmit_unsent == NULL) {
                        /* Nothing to retransmit */
                        if (sctp->sctp_state == SCTPS_SHUTDOWN_PENDING) {
                                sctp_send_shutdown(sctp, 1);
                        }
                        return;
                }

                SCTPS_BUMP_MIB(sctps, sctpTimRetrans);

                sctp_rexmit(sctp, fp);
                /*
                 * sctp_rexmit() will increase the strikes and restart the
                 * timer, so return here.
                 */
                return;
        case SCTPS_COOKIE_WAIT:
                BUMP_LOCAL(sctp->sctp_T1expire);
rxmit_init:
                /* retransmit init */
                /*
                 * We don't take the conn hash lock here since the source
                 * address list won't be modified (it would have been done
                 * the first time around).
                 */
                mp = sctp_init_mp(sctp, fp);
                if (mp != NULL) {
                        SCTPS_BUMP_MIB(sctps, sctpTimRetrans);
                        (void) conn_ip_output(mp, fp->sf_ixa);
                        BUMP_LOCAL(sctp->sctp_opkts);
                }
                rto_max = sctp->sctp_rto_max_init;
                break;
        case SCTPS_COOKIE_ECHOED:
                BUMP_LOCAL(sctp->sctp_T1expire);
                if (sctp->sctp_cookie_mp == NULL) {
                        sctp->sctp_state = SCTPS_COOKIE_WAIT;
                        goto rxmit_init;
                }
                mp = dupmsg(sctp->sctp_cookie_mp);
                if (mp == NULL)
                        break;
                (void) conn_ip_output(mp, fp->sf_ixa);
                BUMP_LOCAL(sctp->sctp_opkts);
                SCTPS_BUMP_MIB(sctps, sctpTimRetrans);
                rto_max = sctp->sctp_rto_max_init;
                break;
        case SCTPS_SHUTDOWN_SENT:
                BUMP_LOCAL(sctp->sctp_T2expire);
                sctp_send_shutdown(sctp, 1);
                SCTPS_BUMP_MIB(sctps, sctpTimRetrans);
                break;
        case SCTPS_SHUTDOWN_ACK_SENT:
                /* We shouldn't have any more outstanding data */
                ASSERT(sctp->sctp_xmit_head == NULL);
                ASSERT(sctp->sctp_xmit_unsent == NULL);

                BUMP_LOCAL(sctp->sctp_T2expire);
                (void) sctp_shutdown_received(sctp, NULL, B_FALSE, B_TRUE,
                    NULL);
                SCTPS_BUMP_MIB(sctps, sctpTimRetrans);
                break;
        default:
                ASSERT(0);
                break;
        }

        fp->sf_strikes++;
        sctp->sctp_strikes++;
        SCTP_CALC_RXT(sctp, fp, rto_max);

        SCTP_FADDR_TIMER_RESTART(sctp, fp, fp->sf_rto);
}

/*
 * RTO calculation. timesent and now are both in ms.
 */
void
sctp_update_rtt(sctp_t *sctp, sctp_faddr_t *fp, clock_t delta)
{
        int rtt;

        /* Calculate the RTT in ms */
        rtt = (int)delta;
        rtt = rtt > 0 ? rtt : 1;

        dprint(5, ("sctp_update_rtt: fp = %p, rtt = %d\n", (void *)fp, rtt));

        /* Is this the first RTT measurement? */
        if (fp->sf_srtt == -1) {
                fp->sf_srtt = rtt;
                fp->sf_rttvar = rtt / 2;
                fp->sf_rto = 3 * rtt; /* == rtt + 4 * rttvar ( == rtt / 2) */
        } else {
                int abs;
                /*
                 * Versions of the RTO equations that use fixed-point math.
                 * alpha and beta are NOT tunable in this implementation,
                 * and so are hard-coded in. alpha = 1/8, beta = 1/4.
                 */
                abs = fp->sf_srtt - rtt;
                abs = abs >= 0 ? abs : -abs;
                fp->sf_rttvar = (3 * fp->sf_rttvar + abs) >> 2;
                fp->sf_rttvar = fp->sf_rttvar != 0 ? fp->sf_rttvar : 1;

                fp->sf_srtt = (7 * fp->sf_srtt + rtt) >> 3;
                fp->sf_rto = fp->sf_srtt + 4 * fp->sf_rttvar;
        }

        dprint(5, ("sctp_update_rtt: srtt = %d, rttvar = %d, rto = %d\n",
            fp->sf_srtt, fp->sf_rttvar, fp->sf_rto));

        /* Bound the RTO by configured min and max values */
        if (fp->sf_rto < sctp->sctp_rto_min) {
                fp->sf_rto = sctp->sctp_rto_min;
        }
        if (fp->sf_rto > sctp->sctp_rto_max) {
                fp->sf_rto = sctp->sctp_rto_max;
        }

        SCTP_MAX_RTO(sctp, fp);
        fp->sf_rtt_updates++;
}

void
sctp_free_faddr_timers(sctp_t *sctp)
{
        sctp_faddr_t *fp;

        for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
                if (fp->sf_timer_mp != NULL) {
                        sctp_timer_free(fp->sf_timer_mp);
                        fp->sf_timer_mp = NULL;
                        fp->sf_timer_running = 0;
                }
                if (fp->sf_rc_timer_mp != NULL) {
                        sctp_timer_free(fp->sf_rc_timer_mp);
                        fp->sf_rc_timer_mp = NULL;
                        fp->sf_rc_timer_running = 0;
                }
        }
}

void
sctp_stop_faddr_timers(sctp_t *sctp)
{
        sctp_faddr_t *fp;

        for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
                SCTP_FADDR_TIMER_STOP(fp);
                SCTP_FADDR_RC_TIMER_STOP(fp);
        }
}

void
sctp_process_timer(sctp_t *sctp)
{
        mblk_t *mp;

        ASSERT(sctp->sctp_running);
        ASSERT(MUTEX_HELD(&sctp->sctp_lock));
        while ((mp = sctp->sctp_timer_mp) != NULL) {
                ASSERT(DB_TYPE(mp) == M_PCSIG);
                /*
                 * Since the timer mblk can be freed in sctp_timer_call(),
                 * we need to grab the b_cont before that.
                 */
                sctp->sctp_timer_mp = mp->b_cont;
                mp->b_cont = NULL;
                /*
                 * We have a reference on the sctp, the lock must be
                 * dropped to avoid deadlocks with functions potentially
                 * called in this context which in turn call untimeout().
                 */
                mutex_exit(&sctp->sctp_lock);
                sctp_timer_call(sctp, mp);
                mutex_enter(&sctp->sctp_lock);
        }
        SCTP_REFRELE(sctp);
}