/*****************************************************************************

 @(#) $Id: sli_sm.c,v 0.7.2.10 2001/02/03 05:48:51 brian Test $

 -----------------------------------------------------------------------------

 Copyright (C) 1997-2001  Brian Bidulock <bidulock@dallas.net>

 All Rights Reserved.

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 675 Mass
 Ave, Cambridge, MA 02139, USA.

 -----------------------------------------------------------------------------

 Last Modified $Date: 2001/02/03 05:48:51 $ by $Author: brian $

 *****************************************************************************/

static char const ident[] = "$Id: sli_sm.c,v 0.7.2.10 2001/02/03 05:48:51 brian Test $";

#include "sli_sm.h"

#define sl_timer_stop(tim) \
{ \
    if ( sl_timers. # tim # ) \
        untimeout(sl_timers. # tim # ); \
}

#define sl_timer_start(tim) \
{ \
    sl_timer_stop(tim); \
    sl->timers. # tim = \
      timeout((timo_fcn_t)sl_ # tim # _timeout, (caddr_t)sl, sl->config. # tim # ); \
}

#define sl_timer_start_t4(val) \
{ \
    sl_timer_stop(t4); \
    sl->timers.t4 = \
      timeout((timo_fcn_t)sl_t4_timeout, (caddr_t)sl, sl->statem. # val # ); \
}

static inline void sl_send_fisu(sl_t *sl)
{
    if ( sl->config.popt & SL_POPT_XSN ) {
        /* FIXME: use preallocated dmabufs */
        mblk_t *mp = allocb(6, BPRI_HI); if ( mp == NULL ) return;
        unsigned short *p = (unsigned short *)mp->b_wptr;
        *p++ = (sl->statem.tx.N.bsn|sl->statem.tx.N.bib);
        *p++ = (sl->statem.tx.N.fsn|sl->statem.tx.N.fib);
        *p++ = 0;
        mp->b_wptr = (void*)p;
    } else {
        /* FIXME: use preallocated dmabufs */
        mblk_t *mp = allocb(3, BPRI_HI); if ( mp == NULL ) return;
        *(mp->b_wptr)++ = (sl->statem.tx.N.bsn|sl->statem.tx.N.bib);
        *(mp->b_wptr)++ = (sl->statem.tx.N.fsn|sl->statem.tx.N.fib);
        *(mp->b_wptr)++ = 0;
    }
    putnext(sl->wq, mp);
    sl->devops->send(sl, mp);
}

static inline void sl_send_lssu(sl_t *sl)
{
    if ( sl->config.popt & SL_POPT_XSN ) {
        mblk_t *mp = allocb(7, BPRI_HI); if ( mp == NULL ) return;
        unsigned short *p = (unsigned short *)mp->b_wptr;
        *p++ = (sl->statem.tx.N.bsn|sl->statem.tx.N.bib);
        *p++ = (sl->statem.tx.N.fsn|sl->statem.tx.N.fib);
        *p++ = 0;
        mp->b_wptr = (void*)p;
        *(mp->b_wptr)++ = (sl->statem.tx.sio);
    } else {
        /* FIXME: use preallocated dmabufs */
        mblk_t *mp = allocb(4, BPRI_HI); if ( mp == NULL ) return;
        *(mp->b_wptr)++ = (sl->statem.tx.N.bsn|sl->statem.tx.N.bib);
        *(mp->b_wptr)++ = (sl->statem.tx.N.fsn|sl->statem.tx.N.fib);
        *(mp->b_wptr)++ = 1;
        *(mp->b_wptr)++ = (sl->statem.tx.sio);
    }
    sl->devops->send(sl, mp);
}


static inline void sl_send_msu(sl_t *sl, mblk_t *mp)
{
    unsigned int len;
    if ( sl->config.popt & SL_POPT_XSN ) {
        unsigned short *p = (unsigned short *)mp->b_rptr;
        len = (unsigned int)(mp->b_wptr - mp->b_rptr - 6);
        p[0] = (sl->statem.tx.N.bsn|sl->statem.tx.N.bib);
        p[1] = (sl->statem.tx.N.fsn|sl->statem.tx.N.fib);
        p[2] = (len<512?len:511);
    } else {
        len = (unsigned int)(mp->b_wptr - mp->b_rptr - 3);
        mp->b_rptr[0] = (sl->statem.tx.N.bsn|sl->statem.tx.N.bib);
        mp->b_rptr[1] = (sl->statem.tx.N.fsn|sl->statem.tx.N.fib);
        mp->b_rptr[2] = (len<64?len:63);
    }
    sl->devops->send(sl, mp);
}
/*
 *  -----------------------------------------------------------------------
 *
 *  UPSTREAM Protocol Primitives
 *
 *  -----------------------------------------------------------------------
 */

typedef void (*sl_func_t)(sl_t *);

static void
sl_bufcall(sl_t *sl, unsigned size, sl_func_t call)
{
    (void)sl;
    (void)call;
    /* FIXME: get bufcalls working */
#if 0
    int i;
    for ( i=0; i < SL_MAX_BUFFCALLS; i++ )
        if ( !sl->bufids[i] ) break;
    if ( i >= SL_MAX_BUFCALLS ) return;
    sl->bufids[i] = bufcall(size, BPRI_HI, (void(*)(long))call, (long)sl);
#endif
}

static inline void
sl_cmd_prim(sl_t *sl, sl_func_t call, int type, sl_ulong cmd)
{
    mblk_t *mp;
    if ( (mp = allocb(sizeof(cmd), BPRI_HI)) ) {
        mp->b_datap->db_type = type;
        *((sl_ulong *)mp->b_wptr) = cmd;
        mp->b_wptr += sizeof(cmd);
        putnext(sl->rq, mp);
        return;
    }
    sl_bufcall(sl, sizeof(cmd), call);
}

static inline int
sl_cmd_link(sl_t *sl, int type, sl_ulong cmd, mblk_t *md)
{
    mblk_t *mp;
    if ( (mp = allocb(sizeof(cmd), BPRI_HI)) ) {
        mp->b_datap->db_type = type;
        *((sl_ulong *)mp->b_wptr) = cmd;
        mp->b_wptr += sizeof(cmd);
        linkb(mp, md);
        putnext(sl->rq, mp);
        return;
    }
    return ENOBUFS;
}

static inline void
sl_evt_arg(sl_t *sl, sl_func_t call, int type, sl_ulong cmd, sl_ulong arg)
{
    mblk_t *mp;
    if ( (mp = allocb(SL_CMD_ARG_SIZE + SL_EVENT_HEADER_LEN, BPRI_HI)) ) {
        mp->b_rptr += SL_EVENT_HEADER_LEN;
        sl_cmd_arg_t *p = (sl_cmd_arg_t *)mp->b_rptr;
        mp->b_datap->db_type = type;
        p->sl_cmd = cmd;
        p->sl_arg = arg;
        mp->b_wptr = (void *)(p+1);
        putnext(sl->rq, mp);
        return;
    }
    sl_bufcall(sl, SL_CMD_ARG_SIZE+SL_EVENT_HEADER_LEN, call);
}

static inline void
sl_cmd_arg(sl_t *sl, sl_func_t call, int type, sl_ulong cmd, sl_ulong arg)
{
    mblk_t *mp;
    if ( (mp = allocb(SL_CMD_ARG_SIZE, BPRI_HI)) ) {
        sl_cmd_arg_t *p = (sl_cmd_arg_t *)mp->b_wptr;
        mp->b_datap->db_type = type;
        p->sl_cmd = cmd;
        p->sl_arg = arg;
        mp->b_wptr += SL_CMD_ARG_SIZE;
        putnext(sl->rq, mp);
        return;
    }
    sl_bufcall(sl, SL_CMD_ARG_SIZE, call);
}

static inline void
sl_evt_2arg(sl_t *sl, sl_func_t call, int type, sl_ulong cmd, sl_ulong arg1, sl_ulong arg2)
{
    mblk_t *mp;
    if ( (mp = allocb(SL_CMD_2ARG_SIZE + SL_EVENT_HEADER_LEN, BPRI_HI)) ) {
        mp->b_rptr += SL_EVENT_HEADER_LEN;
        sl_cmd_2arg_t *p = (sl_cmd_2arg_t *)mp->b_rptr;
        mp->b_datap->db_type = type;
        p->sl_cmd = cmd;
        p->sl_arg1 = arg1;
        p->sl_arg2 = arg2;
        mp->b_wptr = (void *)(p+1);
        putnext(sl->rq, mp);
        return;
    }
    sl_bufcall(sl, SL_CMD_2ARG_SIZE+SL_EVENT_HEADER_LEN, call);
}

static inline void
sl_cmd_2arg(sl_t *sl, sl_func_t call, int type, sl_ulong cmd, sl_ulong arg1, sl_ulong arg2)
{
    mblk_t *mp;
    if ( (mp = allocb(SL_CMD_2ARG_SIZE, BPRI_HI)) ) {
        mp->b_datap->db_type = type;
        sl_cmd_2arg_t *p = (sl_cmd_2arg_t *)mp->b_wptr;
        p->sl_cmd = cmd;
        p->sl_arg1 = arg1;
        p->sl_arg2 = arg2;
        mp->b_wptr += SL_CMD_2ARG_SIZE;
        putnext(sl->rq, mp);
        return;
    }
    sl_bufcall(sl, SL_CMD_2ARG_SIZE, call);
}

static inline void
sl_evt_3arg(sl_t *sl, sl_func_t call, int type, sl_ulong cmd, sl_ulong arg1, sl_ulong arg2, sl_ulong arg3)
{
    mblk_t *mp;
    if ( (mp = allocb(SL_CMD_3ARG_SIZE + SL_EVENT_HEADER_LEN, BPRI_HI)) ) {
        mp->b_rptr += SL_EVENT_HEADER_LEN;
        sl_cmd_3arg_t *p = (sl_cmd_3arg_t *)mp->b_rptr;
        mp->b_datap->db_type = type;
        p->sl_cmd = cmd;
        p->sl_arg1 = arg1;
        p->sl_arg2 = arg2;
        p->sl_arg3 = arg3;
        mp->b_wptr = (void *)(p+1);
        putnext(sl->rq, mp);
        return;
    }
    sl_bufcall(sl, SL_CMD_3ARG_SIZE+SL_EVENT_HEADER_LEN, call);
}

static inline void
sl_cmd_3arg(sl_t *sl, sl_func_t call, int type, sl_ulong cmd, sl_ulong arg1, sl_ulong arg2, sl_ulong arg3)
{
    mblk_t *mp;
    if ( (mp = allocb(SL_CMD_3ARG_SIZE, BPRI_HI)) ) {
        mp->b_datap->db_type = type;
        sl_cmd_3arg_t *p = (sl_cmd_3arg_t *)mp->b_wptr;
        p->sl_cmd = cmd;
        p->sl_arg1 = arg1;
        p->sl_arg2 = arg2;
        p->sl_arg3 = arg3;
        mp->b_wptr += SL_CMD_3ARG_SIZE;
        putnext(sl->rq, mp);
        return;
    }
    sl_bufcall(sl, SL_CMD_3ARG_SIZE, call);
}

static inline void
sl_l3_pdu(sl_t *sl, mblk_t *md)
{
    sl_peg_count(&sl->stats.sl_recv_msus);
    if ( sl_cmd_link(sl, M_PROTO, SL_PDU_IND, md) )
        putnext(sl->rq, md);
}

static inline void
sl_l3_link_congested(sl_t *sl)
{
    sl_cmd_3arg(sl, sl_l3_link_congested,
            M_PCPROTO, SL_LINK_CONGESTED_IND,
            sl->statem.cong_level, sl->statem.disc_level, 0);
}

static inline void
sl_l3_link_congested_event(sl_t *sl)
{
    sl_evt_3arg(sl, sl_l3_link_congested_event,
            M_PCPROTO, SL_LINK_CONGESTED_IND,
            jiffies, sl->statem.cong_level, sl->statem.disc_level);
}

static inline void
sl_l3_link_congestion_ceased(sl_t *sl)
{
    sl_cmd_3arg(sl, sl_l3_link_congestion_ceased,
            M_PCPROTO, SL_LINK_CONGESTED_CEASED_IND,
            0, sl->statem.cong_level, sl->statem.disc_level);
}

static inline int
sl_l3_retrieved_message(sl_t *sl, mblk_t *md)
{
    return sl_cmd_link(sl,
            M_PCPROTO, SL_RETRIEVED_MESSAGE_IND, md);
}

static inline void
sl_l3_retrieval_complete(sl_t *sl)
{
    sl_cmd_prim(sl, sl_retrieval_complete,
            M_PCPROTO, SL_RETRIEVAL_COMPLETE_IND);
}

static inline void
sl_l3_rb_cleared(sl_t *sl)
{
    sl_cmd_prim(sl, sl_rb_cleared,
            M_PCPROTO, SL_RB_CLEARED_IND);
}

static inline void
sl_l3_bsnt(sl_t *sl) {
    sl_cmd_arg(sl, sl_l3_bsnt,
            M_PCPROTO, SL_BSNT_IND, sl->statem.rx.T.bsn);
}

static inline void
sl_l3_in_service(sl_t *sl)
{
    sl_cmd_prim(sl, sl_in_service,
            M_PCPROTO, SL_IN_SERVICE_IND);
}

static inline void
sl_l3_out_of_service(sl_t *sl)
{
    if ( sl->statem.failure_reason & sl->notify.events &
            SL_EVT_FAIL_ALL_REASONS )
        sl_evt_2arg(sl, sl_out_of_service,
                M_PCPROTO, SL_OUT_OF_SERVICE_IND,
                jiffies, sl-statem.failure_reason);
    else
        sl_cmd_2arg(sl, sl_out_of_service,
                M_PCPROTO, SL_OUT_OF_SERVICE_IND,
                0, sl-statem.failure_reason);
}

static inline void
sl_l3_remote_processor_outage(sl_t *sl)
{
    if ( sl->notify.events & SL_EVT_RPO_BEGIN )
        sl_evt_arg(sl, sl_remote_processor_outage,
                M_PCPROTO, SL_REMOTE_PROCESSOR_OUTAGE_IND,
                jiffies);
    else
        sl_cmd_arg(sl, sl_remote_processor_outage,
                M_PCPROTO, SL_REMOTE_PROCESSOR_OUTAGE_IND,
                0);
}

static inline void
sl_l3_remote_processor_recovered(sl_t *sl)
{
    if ( sl->notify.events & SL_EVT_RPO_END )
        sl_evt_arg(sl, sl_remote_processor_outage,
                M_PCPROTO, SL_REMOTE_PROCESSOR_RECOVERED_IND,
                jiffies);
    else
        sl_cmd_arg(sl, sl_remote_processor_recovered,
                M_PCPROTO, SL_REMOTE_PROCESSOR_RECOVERED_IND,
                0);
}

static inline void
sl_l3_rtb_cleared(sl_t *sl)
{
    sl_cmd_prim(sl, sl_rtb_cleared,
            M_PCPROTO, SL_RTB_CLEARED_IND);
}

/*
 *  -----------------------------------------------------------------------
 *
 *  STATE MACHINES:- The order of the state machine primitives below may
 *  seem somewhat disorganized at first glance; however, they have been
 *  ordered by dependency because they are all inline functions.  You
 *  see, the L2 state machine does not required multiple threading
 *  because there is never a requirement to invoke the individual state
 *  machines concurrently.  This works out good for the driver, because
 *  a primitive action expands inline to the necessary procedure, while
 *  the source still takes the appearance of the SDL diagrams in the SS7
 *  specification for inspection and debugging.
 *
 *  -----------------------------------------------------------------------
 */

/*
 *  Note that the receivers (DAEDR) are not started for SS7 at power-on.
 *  It is only after L2 receives the SL_START primitive from L3 that the
 *  receivers are started.  Once started, however, the receivers are
 *  never stopped or reset.  In contrast, the transmitters (DAEDT) are
 *  started initially at power-on and are never restarted.  Transmitters
 *  are supposed to send SIOS at power-on.
 */

/* Inspected to Figure 11/Q.703 (03/93) (sheet 1 of 2) */
/* Inspected to Figure 11/T1.111.3-1992 */
static inline void sl_daedr_start(sl_t *sl) 
{
    if ( sl->statem.daedr_state == SL_STATE_IDLE ) {
        /*  FIXME:  functions must be performed to
         *          actually start receivers */
        /*
         *  We should use a hook here, so that the state machine calls
         *  some driver hook function, say sl->sl_dev->daedr_start();
         */
        sl->statem.daedr_state = SL_STATE_IN_SERVICE;
    }
}


/* Inspected to Figure 18/Q.703 (03/93) */
/* Inspected to Figure 18/T1.111.3-1992 */
static inline void sl_suerm_stop(sl_t *sl) 
{
    sl->statem.suerm_state = SL_STATE_IDLE;
}

static inline void sl_eim_stop(sl_t *sl)
{
    sl->statem.eim_state = SL_STATE_IDLE;
}

/* Inspected to Figure 19/Q.703 (03/93) */
/* Inspected to Figure 19/T1.111.3-1992 */
#define sl_cc_stop sl_cc_normal
static inline void sl_cc_normal(sl_t *sl) 
{
    sl_timer_stop(t5);
    sl->statem.cc_state = SL_STATE_IDLE;
}

/* Inspected to Figure 14/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 16/Q.703 (03/93) (sheet 2 of 6) */
/* Inspected to Figure 14/T1.111.3-1992 (sheet 4 of 4) */
/* Inspected to Figure 16/T1.111.3-1992 (sheet 2 of 3) */
static inline void sl_rc_stop(sl_t *sl) 
{
    sl_cc_normal(sl);
    sl->statem.rc_state = SL_STATE_IDLE;
}

/* Inspected to Figure 9/Q.703 (03/93) (sheet 1 of 6) */
/* Inspected to Figure 9/T1.111.3-1992 (sheet 1 of 3) */
/* Inspected to Figure 9/Q.703 (03/93) (sheet 4 of 6) */
/* Inspected to Figure 9/T1.111.3-1992 (sheet 2 of 3) */
/* Inspected to Figure 9/Q.703 (03/93) (sheet 5 of 6) */
/* Inspected to Figure 9/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_iac_stop(sl_t *sl) 
{
    if ( sl->statem.iac_state != SL_STATE_IDLE ) {
            sl_timer_stop(t3);
            sl_timer_stop(t2);
            sl_timer_stop(t4);
            sl_aerm_stop(sl);
            sl->statem.emergency = 0;
            sl->statem.iac_state = SL_STATE_IDLE;
    }
}


static inline void sl_daedt_transmitter_wakeup(sl_t *sl) 
{
    /* Inspected to Figure 12/Q.703 (03/93) */
    /* Inspected to Figure 12/T1.111.3-1992 */
    if ( sl->statem.daedt_state == SL_STATE_SLEEPING )
        sl->statem.daedt_state = SL_STATE_IN_SERVICE;
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 3 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 2 of 3) */
static inline void sl_txc_send_sios(sl_t *sl) 
{
    sl_timer_stop(t7);
    if ( sl->config.pvar == SS7_PVAR_ANSI_92 )
        sl_timer_stop(t6);
    sl->statem.lssu_available = 1;
    sl->statem.tx.sio = LSSU_SIOS;
    sl_daedt_transmitter_wakeup(sl);
}


/* Inspected to Figure 8/Q.703 (03/93) (sheet 5 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 5 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 3 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 8 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 8 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 5 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 6 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 6 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 4 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 10 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 10 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 6 of 7) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 14 of 14) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 14 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
static inline void sl_lsc_link_failure(sl_t *sl) 
{
    if ( sl->statem.lsc_state != SL_STATE_OUT_OF_SERVICE ) {
        sl_l3_out_of_service(sl);
        sl_iac_stop(sl);                        /* ok if not aligning */
        sl_timer_stop(t1);                      /* ok if not running */
        sl_suerm_stop(sl);                      /* ok if not running */
        sl_eim_stop(sl);                        /* ok if not running */
        sl_rc_stop(sl);
        sl_txc_send_sios(sl);
        sl_poc_stop(sl);                        /* ok if not ITUT */
        sl->statem.emergency = 0;
        sl->statem.flags &= ~SL_F_LOCAL_PROCESSOR_OUTAGE;
        sl->statem.local_processor_outage = 0;
        sl->statem.remote_processor_outage = 0; /* ok if not ANSI */
        sl->statem.lsc_state = SL_STATE_OUT_OF_SERVICE;
    }
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 2 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 3 of 3) */
static void sl_t6_timeout(sl_t *sl) 
{
    sl->statem.failure_reason = SL_FAIL_CONG_TIMEOUT;
    sl_lsc_link_failure(sl);
    sl->statem.sib_received = 0;
    sl_timer_stop(t7);
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 5 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 5 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 5 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 5 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 2 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 3 of 3) */
static void sl_t7_timeout(sl_t *sl) 
{
    sl->statem.failure_reason = SL_FAIL_ACK_TIMEOUT;
    sl_lsc_link_failure(sl);
    sl_timer_stop(t6);
    if ( sl->config.pvar == SS7_PVAR_ITUT_96 )
        sl->statem.sib_received = 0;
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 3 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 2 of 3) */
static inline void sl_txc_send_sib(sl_t *sl) 
{
    sl->statem.lssu_available = 1;
    sl->statem.tx.sio = LSSU_SIB;
    sl_daedt_transmitter_wakeup(sl);
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 3 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 2 of 3) */
static inline void sl_txc_send_sipo(sl_t *sl) 
{
    sl_timer_stop(t7);
    if ( sl->config.pvar == SS7_PVAR_ANSI_92 ) sl_timer_stop(t6);
    sl->statem.lssu_available = 1;
    sl->statem.tx.sio = LSSU_SIPO;
    sl_daedt_transmitter_wakeup(sl);
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 2 of 3) */
static inline void sl_txc_send_sio(sl_t *sl) 
{
    sl->statem.lssu_available = 1;
    sl->statem.tx.sio = LSSU_SIO;
    sl_daedt_transmitter_wakeup(sl);
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 2 of 3) */
static inline void sl_txc_send_sin(sl_t *sl) 
{
    sl->statem.lssu_available = 1;
    sl->statem.tx.sio = LSSU_SIN;
    sl_daedt_transmitter_wakeup(sl);
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 2 of 3) */
static inline void sl_txc_send_sie(sl_t *sl) 
{
    sl->statem.lssu_available = 1;
    sl->statem.tx.sio = LSSU_SIE;
    sl_daedt_transmitter_wakeup(sl);
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 5 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 5 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 5 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 5 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 3 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 2 of 3) */
static inline void sl_txc_send_msu(sl_t *sl) 
{
    if ( sl->rtb->q_count ) sl_timer_start(t7);
    sl->statem.msu_inhibited = 0;
    sl->statem.lssu_available = 0;
    sl_daedt_transmitter_wakeup(sl);
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 5 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 5 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 5 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 5 of 7) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 2 of 3) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 3 of 4) */
static inline void sl_txc_send_fisu(sl_t *sl) 
{
    sl_timer_stop(t7);
    if ( sl->config.pvar == SS7_PVAR_ANSI_92 && !(sl->config.popt & SL_POPT_PCR) )
        sl_timer_stop(t6);
    sl->statem.msu_inhibited = 1;
    sl->statem.lssu_available = 0;
    sl_daedt_transmitter_wakeup(sl);
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 6 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 6 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 6 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 6 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 4 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_txc_fsnx_value(sl_t *sl) 
{
    sl->statem.tx.X.fsn = sl->statem.rx.X.fsn;
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 5 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 5 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 4 of 4) */
static inline void sl_txc_nack_to_be_sent(sl_t *sl) 
{
    sl->statem.tx.N.bib = sl->statem.tx.N.bib ?0:sl->statem.ib_mask;
}

/* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
static inline void sl_lsc_rtb_cleared(sl_t *sl) 
{
    if ( sl->statem.lsc_state == SL_STATE_PROCESSOR_OUTAGE ) {
        sl->statem.remote_processor_outage = 0;
        if ( sl->statem.local_processor_outage ) return;
        sl_l3_remote_processor_recovered(sl);
        sl_l3_rtb_cleared(sl);
        sl_txc_send_msu(sl);
        sl->statem.lsc_state = SL_STATE_IN_SERVICE;
    }
}

/* Inspected to Figure 15/T1.111.3-1992 (sheet 3 of 3) */
/* Inspected to Figure 13/Q.703 (03/93) (sheet 6 of 7) */
static inline void sl_txc_bsnr_and_bibr(sl_t *sl) 
{
    sl->statem.tx.R.bsn = sl->statem.rx.R.bsn;
    sl->statem.tx.R.bib = sl->statem.rx.R.bib;
    if ( sl->statem.clear_rtb ) {
        flushq(sl->rtb, FLUSHALL); sl_check_congestion(sl);
        sl->statem.tx.F.fsn = (sl->statem.tx.R.bsn +1)&sl->statem.sn_mask;
        sl->statem.tx.L.fsn = sl->statem.tx.R.bsn;
        sl->statem.tx.N.fsn = sl->statem.tx.R.bsn;
        sl->statem.tx.N.fib = sl->statem.tx.R.bib;
        sl->statem.Z = (statem.tx.R.bsn +1)&sl->statem.sn_mask;
        sl->statem.z_ptr = NULL;
        sl_lsc_rtb_cleared(sl);
        sl->statem.clear_rtb = 0;
        sl->statem.rtb_full = 0;
        return;
    }
    if ( sl->statem.tx.F.fsn != ((sl->statem.tx.R.bsn +1)&sl->statem.sn_mask) ) {
        if ( sl->statem.sib_received ) {
            sl->statem.sib_received = 0;
            sl_timer_stop(t6);
        }
        do {
            freemsg(getq(sl->rtb));
            sl->statem.tx.F.fsn = (sl->statem.tx.F.fsn +1)&sl->statem.sn_mask;
        } while ( sl->statem.tx.F.fsn != ((sl->statem.tx.R.bsn +1)&sl->statem.sn_mask) );
        sl_check_congestion(sl);
        sl_daedt_transmitter_wakeup(sl);
        if ( sl->rtb->q_count == 0 ) {
            sl_timer_stop(t7);
        } else {
            sl_timer_start(t7);
        }
        sl->statem.rtb_full = 0;
        if ( SN_OUTSIDE(sl->statem.F.fsn, sl->statem.Z, sl->statem.L.fsn) )
            sl->statem.Z = sl->satem.tx.F.fsn;
    }
    if ( sl->config.popt & SL_POPT_PCR ) return;
    if ( sl->statem.tx.N.fib != sl->statem.tx.R.bib ) {
        if ( sl->statem.sib_received ) {
            sl->statem.sib_received = 0;
            sl_timer_stop(t6);
        }
        sl->statem.tx.N.fib = sl->statem.tx.R.bib;
        sl->statem.tx.N.fsn = (sl->statem.tx.F.fsn -1)&sl->statem.sn_mask;
        if ( (sl->statem.z_ptr = sl->rtb->q_first) != NULL )
            sl->statem.retrans_cycle = 1;
        sl_daedt_transmitter_wakeup(sl);
        return;
    }
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 5 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 5 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 5 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 5 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 4 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_txc_sib_received(sl_t *sl) 
{
    /* FIXME: consider these variations for all */
    if ( sl->config.pvar == SS7_PVAR_ANSI_92 && sl->statem.lssu_available )
        if ( sl->statem.tx.sio != LSSU_SIB ) return;
    if ( sl->config.pvar != SS7_PVAR_ITUT_93 && !sl->rtb->q_count )
        return;
    if ( ! sl->statem.sib_received ) {
        sl_timer_start(t6);
        sl->statem.sib_received = 1;
    }
    sl_timer_start(t7);
}

/* Inspected to Figure 13/T1.111.3-1992 (sheet 2 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_txc_clear_rtb(sl_t *sl) 
{
    flushq(sl->rtb, FLUSHDATA);
    sl->statem.clear_rtb = 1;
    sl->statem.rtb_full = 0;  /* added */
    /* FIXME: should probably follow more of the ITUT flush_buffers stuff like
     * reseting Z and FSNF, FSNL, FSNT. */
    sl_check_congestion(sl);
}

/* Inspected to Figure 13/T1.111.3-1992 (sheet 2 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_txc_clear_tb(sl_t *sl) 
{
    flushq(sl->tb, FLUSHDATA);
    sl->statem.Cm = 0;
    sl_check_congestion(sl);
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 7 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 7 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 7 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 7 of 7) */
static inline void sl_txc_flush_buffers(sl_t *sl)
{
    flushq(sl->rtb, FLUSHDATA);
    flushq(sl->tb, FLUSHDATA);
    sl->statem.rtb_full = 0;
    sl->statem.Cm = 0;
    sl->statem.Z = 0; sl->statem.z_ptr = NULL;
    /* Z =0 error in ITUT 93 and ANSI */
    sl->statem.Z = sl->statem.tx.F.fsn = (sl->statem.tx.R.bsn +1)&sl->statem.sn_mask;
    sl->statem.tx.L.fsn = sl->statem.rx.R.bsn;
    sl->statem.tx.T.fsn = sl->statem.rx.R.bsn;
    sl_timer_stop(t7);
    return;
}

/* Inspected to Figure 12/Q.703 (03/93) */
/* Inspected to Figure 12/Q.703 (07/96) */
/* Inspected to Figure 12/T1.111.3-1992 */
static inline void sl_daedt_fisu(sl_t *sl) 
{
    sl_send_fisu(sl);
    sl->statem.daedt_state = SL_STATE_SLEEPING;
}

/* Inspected to Figure 12/Q.703 (03/93) */
/* Inspected to Figure 12/Q.703 (07/96) */
/* Inspected to Figure 12/T1.111.3-1992 */
static inline void sl_daedt_lssu(sl_t *sl) 
{
    sl_send_lssu(sl);
    if ( sl->statem.lssu_available )
        sl->statem.daedt_state = SL_STATE_SLEEPING;
}

/* Inspected to Figure 12/Q.703 (03/93) */
/* Inspected to Figure 12/Q.703 (07/96) */
/* Inspected to Figure 12/T1.111.3-1992 */
static inline void sl_daedt_msu(sl_t *sl, mblk_t *mp) 
{
    sl_send_msu(sl, mp);
}

/* Inspected to Figure 14/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 16/Q.703 (03/93) (sheet 2 of 6) */
/* Inspected to Figure 14/Q.703 (07/96) (sheet 2 of 7) */
/* Inspected to Figure 16/Q.703 (07/96) (sheet 2 of 6) */
/* Inspected to Figure 14/T1.111.3-1992 (sheet 2 of 4) */
/* Inspected to Figure 16/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_rc_fsnt_value(sl_t *sl) 
{
    sl->statem.rx.T.fsn = sl->statem.tx.N.fsn;
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 6 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 6 of 7) */
/* Inspected to Figure 13/Q.703 (07/96) (sheet 6 of 7) */
/* Inspected to Figure 15/Q.703 (07/96) (sheet 6 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 3 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_txc_retrieval_request_and_fsnc(sl_t *sl, mblk_t *mp)
{
    union SL_primitive *p = (union SL_primitive *)mp->m_rptr;
    unsigned char fsnc =
        sl->statem.tx.C.fsn = 
        p->retrieval_req_and_fsnc.sl_fsnc &sl->statem.sn_mask;
    while ( sl->rtb->q_count && sl->statem.tx.F.fsn != (fsnc +1)&sl->statem.sn_mask ) {
        freemsg(getq(sl->rtb));
        sl->statem.tx.F.fsn = (sl->statem.tx.F.fsn +1)&sl->statem.sn_mask;
    }
    while ( (mp = getq(sl->tb)) ) {
        sl->statem.Cm--;
        putq(sl->rtb, mp);
    }
    sl->statem.Z = sl->statem.tx.F.fsn = (sl->statem.tx.C.fsn +1)&sl->statem.sn_mask;
    qenable(sl->rtb);
    /* let sl_xqsrv transfer messages and do last part of SDL */
}

/*
 *  sl_xqsrv must do following...
 */
static void sl_xqsrv(queue_t *rtb)
{
    mblk_t *mp;
    sl_t *sl = rtb->q_ptr;

    while ( (mp = getq(rtb)) ) {
        if ( !canputnext(sl->rq) ) {
            putbq(rtb, mp);
            qenable(rtb);
            return;
        }
        if ( sl_l3_retrieved_message(sl, mp) ) {
            putbq(rtb, mp);
            qenable(rtb);
            return;
        }
    }
    sl->statem.rtb_full = 0;
    sl_l3_retrieval_complete(sl);
    sl->statem.Cm = 0;
    sl->statem.tx.N.fsn = sl->statem.tx.L.fsn = sl->statem.tx.C.fsn;
    noenable(q);
}

/* Inspected to Figure 15/T1.111.3-1992 (sheet 2 of 3) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 2 of 4) */
static inline void sl_txc_transmission_request(sl_t *sl) 
{
    int pcr = sl->config.popt & SL_POPT_PCR;

    if ( sl->statem.lssu_available ) {
        if ( sl->statem.tx.sio == LSSU_SIB )
            sl->statem.lssu_available = 0;
        sl->statem.tx.N.fsn = sl->statem.tx.L.fsn;
     /* sl->statem.tx.N.bib = sl->statem.tx.N.bib; */
        sl->statem.tx.N.bsn = (sl->statem.tx.X.fsn - 1)&sl->statem.sn_mask;
     /* sl->statem.tx.N.fib = sl->statem.tx.N.fib; */
        sl_daedt_lssu(sl);
        return;
    }
    if ( sl->statem.msu_inhibited ) {
        sl->statem.tx.N.fsn = sl->statem.tx.L.fsn;
     /* sl->statem.tx.N.bib = sl->statem.tx.N.bib; */
        sl->statem.tx.N.bsn = (sl->statem.tx.X.fsn - 1)&sl->statem.sn_mask;
     /* sl->statem.tx.N.fib = sl->statem.tx.N.fib; */
        sl_daedt_fisu(sl);
        return;
    }
    if ( pcr ) {
        if ( !sl->rtb->q_count ) {
            sl->statem.forced_retransmission = 0;
            sl->statem.rtb_full = 0;
        }
        if ( sl->tb->q_count && sl->statem.rtb_full ) {
            sl->statem.forced_retransmission = 1;
        }
    }
    if ( (!pcr && sl->statem.retrans_cycle) ||
         ( pcr && ( sl->statem.forced_retransmission || ( !sl->tb->q_count && sl->rtb->q_count ) ) ) ) {
        mblk_t *mp = sl->statem.z_ptr;
        sl->statem.z_ptr = mp->b_next;
        sl->statem.tx.N.fsn = (sl->statem.tx.N.fsn + 1)&sl->statem.sn_mask;
     /* sl->statem.tx.N.bib = sl->statem.tx.N.bib; */
        sl->statem.tx.N.bsn = (sl->statem.tx.X.fsn - 1)&sl->statem.sn_mask;
     /* sl->statem.tx.N.fib = sl->statem.tx.N.fib; */
        sl_daedt_msu(sl, dupb(mp)); /* FIXME: this dupb could fail */
        if ( sl->statem.tx.N.fsn == sl->statem.L.fsn || sl->statem.z_ptr == NULL )
            sl->statem.retrans_cycle = 0;
        return;
    }
    if ( (!pcr && (!sl->tb->q_count || sl->statem.rtb_full) ) ||
         ( pcr && (!sl->tb->q_count && !sl->rtb->q_count ) ) ) {
        sl->statem.tx.N.fsn = sl->statem.tx.L.fsn;
        sl->statem.tx.N.bib = sl->statem.tx.N.bib;
        sl->statem.tx.N.bsn = (sl->statem.tx.X.fsn - 1)&sl->statem.sn_mask;
        sl->statem.tx.N.fib = sl->statem.tx.N.fib;
        sl_daedt_fisu(sl);
        return;
    } else {
        mblk_t *mp;
        if ( !(mp = getq(sl->tb)) ) return;
        sl->statem.Cm--;
        sl->statem.tx.L.fsn = (sl->statem.tx.L.fsn + 1)&sl->statem.sn_mask;
        sl->statem.tx.N.fsn = sl->statem.tx.L.fsn;
        if ( !sl->rtb->q_count )
            sl_timer_start(t7);
        putq(sl->rtb, mp);
        sl_rc_fsnt_value(sl);
        if ( pcr ) {
            if ( ( ((sl->statem.tx.F.fsn > sl->statem.tx.L.fsn)?
                    (sl->statem.tx.F.fsn - sl->statem.tx.L.fsn):
                    (sl->statem.tx.F.fsn + 128 - sl->statem.tx.L.fsn))
                   == sl->config.N1 ) || ( sl->rtb->q_count > sl->config.N2 ) )
            {
                sl->statem.rtb_full = 1;
                sl->statem.forced_retransmission = 1;
            }
        } else {
            if ( !canput(sl->rtb) || sl->statem.tx.L.fsn == ((sl->statem.tx.F.fsn - 2)&sl->statem.sn_mask) )
                sl->statem.rtb_full = 1;
        }
     /* sl->statem.tx.N.bib = sl->statem.tx.N.bib; */
        sl->statem.tx.N.bsn = (sl->statem.tx.X.fsn - 1)&sl->statem.sn_mask;
     /* sl->statem.tx.N.fib = sl->statem.tx.N.fib; */
        sl_daedt_msu(sl, dupb(mp));
    }
}

/* Inspected to Figure 16/Q.703 (03/93) (sheet 1 of 6) */
/* Inspected to Figure 14/Q.703 (03/93) (sheet 1 of 7) */
/* Inspected to Figure 16/T1.111.3-1992 (sheet 1 of 3) */
/* Inspected to Figure 14/T1.111.3-1992 (sheet 1 of 4) */
static inline void sl_rc_start(sl_t *sl) 
{
    if ( sl->statem.rc_state == SL_STATE_IDLE ) {
        sl->statem.rx.X.fsn = 0;
        sl->statem.rx.X.fib = sl->statem.ib_mask;
        sl->statem.rx.F.fsn = 0;
        sl->statem.rx.T.fsn = sl->statem.sn_mask;
        sl->statem.rtr = 0;             /* Basic only (note 1). */
        if ( sl->config.pvar == SS7_PVAR_ANSI_92 )
            sl->statem.msu_fisu_accepted = 1;
        else
            sl->statem.msu_fisu_accepted = 0;
        sl->statem.abnormal_bsnr = 0;
        sl->statem.abnormal_fibr = 0;   /* Basic only (note 1). */
        sl->statem.congestion_discard = 0;
        sl->statem.congestion_accept = 0;
        sl_daedr_start(sl);
        sl->statem.rc_state = SL_STATE_IN_SERVICE;
        return;
        /*
         * Note 1 - Although rtr and abnormal_fibr are only applicable
         *          to the Basic procedure (and not PCR), these state
         *          machine variables are never examined by PCR
         *          routines, so PCR and basic can share the same start
         *          procedures.
         */
    }
}

/* Inspected to Figure 14/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 16/Q.703 (03/93) (sheet 2 of 6) */
/* Inspected to Figure 14/T1.111.3-1992 (sheet 2 of 4) */
/* Inspected to Figure 16/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_rc_reject_msu_fisu(sl_t *sl) 
{
    sl->statem.msu_fisu_accepted = 0;
}

/* Inspected to Figure 14/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 16/Q.703 (03/93) (sheet 2 of 6) */
/* Inspected to Figure 14/T1.111.3-1992 (sheet 2 of 4) */
/* Inspected to Figure 16/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_rc_accept_msu_fisu(sl_t *sl) 
{
    sl->statem.msu_fisu_accepted = 1;
}

/* Inspected to Figure 14/Q.703 (03/93) (sheet 7 of 7) */
/* Inspected to Figure 16/Q.703 (03/93) (sheet 6 of 6) */
/* Inspected to Figure 14/Q.703 (07/96) (sheet 7 of 7) */
/* Inspected to Figure 16/Q.703 (07/96) (sheet 6 of 6) */
static inline void sl_rc_retrieve_fsnx(sl_t *sl)
{
    sl_txc_fsnx_value(sl);  /* error in 93 spec */
    sl->statem.congestion_discard = 0;
    sl->statem.congestion_accept = 0;
    sl_cc_normal(sl);
    sl->statem.rtr = 0; /* basic only */
}

/* Inspected to Figure 14/T1.111.3-1992 (sheet 2 of 4) */
/* Inspected to Figure 16/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_rc_align_fsnx(sl_t *sl) 
{
    sl_txc_fsnx_value(sl);
}

/* Inspected to Figure 14/T1.111.3-1992 (sheet 2 of 4) */
/* Inspected to Figure 16/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_rc_clear_rb(sl_t *sl) 
{
    flushq(sl->q, FLUSHDATA);
    sl_l3_rb_cleared(sl);
}

/* Inspected to Figure 14/Q.703 (03/93) (sheet 1 of 7) */
/* Inspected to Figure 14/Q.703 (03/93) (sheet 6 of 7) */
/* Inspected to Figure 16/Q.703 (03/93) (sheet 1 of 6) */
/* Inspected to Figure 16/Q.703 (03/93) (sheet 5 of 6) */
/* Inspected to Figure 14/T1.111.3-1992 (sheet 1 of 4) */
/* Inspected to Figure 14/T1.111.3-1992 (sheet 4 of 4) */
/* Inspected to Figure 16/T1.111.3-1992 (sheet 1 of 3) */
/* Inspected to Figure 16/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_rc_retrieve_bsnt(sl_t *sl) 
{
    sl->statem.rx.T.bsn = (sl->statem.rx.X.fsn - 1)&0x7F;
    sl_l3_bsnt(sl);
}

/* Inspected to Figure 19/Q.703 (03/93) */
/* Inspected to Figure 19/T1.111.3-1992 */
static void sl_t5_timeout(sl_t *sl) 
{
    if ( sl->statem.cc_state == SL_STATE_CONGESTED ) {
            sl_txc_send_sib(sl);
            sl_timer_start(t5);
    }
}

/* Inspected to Figure 19/Q.703 (03/93) */
/* Inspected to Figure 19/T1.111.3-1992 */
static inline void sl_cc_busy(sl_t *sl) 
{
    if ( sl->statem.cc_state == SL_STATE_NORMAL) {
            sl_txc_send_sib(sl);
            sl_timer_start(t5);
            sl->statem.cc_state = SL_STATE_CONGESTED;
    }
}

/* Inspected to Figure 14/Q.703 (03/93) (sheet 6 of 7) */
/* Inspected to Figure 16/Q.703 (03/93) (sheet 5 of 6) */
/* Inspected to Figure 14/T1.111.3-1992 (sheet 4 of 4) */
/* Inspected to Figure 16/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_rc_congestion_discard(sl_t *sl) 
{
    sl->statem.congestion_discard = 1;
    sl_cc_busy(sl);
}

/* Inspected to Figure 14/Q.703 (03/93) (sheet 6 of 7) */
/* Inspected to Figure 16/Q.703 (03/93) (sheet 5 of 6) */
/* Inspected to Figure 14/T1.111.3-1992 (sheet 4 of 4) */
/* Inspected to Figure 16/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_rc_congestion_accept(sl_t *sl) 
{
    sl->statem.congestion_accept = 1;
    sl_cc_busy(sl);
}

/* Inspected to Figure 16/T1.111.3-1992 (sheet 3 of 3) */
/* Inspected to Figure 16/Q.703 (03/93) (sheet 5 of 6) */
/* Inspected to Figure 14/Q.703 (03/93) (sheet 6 of 7) */
/* Inspected to Figure 14/T1.111.3-1992 (sheet 4 of 4) */
static inline void sl_rc_no_congestion(sl_t *sl) 
{
    sl->statem.congestion_discard = 0;
    sl->statem.congestion_accept = 0;
    sl_cc_normal(sl);
    sl_txc_fsnx_value(sl);
    if ( sl->statem.rtr == 1 ) { /* rtr never set for PCR */
        sl_txc_nack_to_be_sent(sl);
        sl->statem.rx.X.fib = sl->statem.rx.X.fib ?0:sl->statem.ib_mask;
    }
}

static void sl_lsc_congestion_discard(sl_t *sl, mblk_t *mp) 
{
    (void)mp;
    sl_rc_congestion_discard(sl);
    sl->statem.l3_congestion_detect = 1;
}

static void sl_lsc_congestion_accept(sl_t *sl, mblk_t *mp) 
{
    (void)mp;
    sl_rc_congestion_accept(sl);
    sl->statem.l3_congestion_detect = 1;
}

static void sl_lsc_no_congestion(sl_t *sl, mblk_t *mp) 
{
    (void)mp;
    sl_rc_no_congestion(sl);
    sl->statem.l3_congestion_detect = 0;
}

/*
 *  --------------------------------------------------------------------------
 *
 *  These congestion functions are implementation dependent.  We should
 *  define a congestion onset level and set congestion accept at that
 *  point.  We should also define a second congestion onset level and
 *  set congestion discard at that point.  For STREAMS, the upstream
 *  congestion can be detected in two ways: 1) canputnext(): is the
 *  upstream module flow controlled; and, 2) canput(): are we flow
 *  controlled.  If the upstream module is flow controlled, then we can
 *  accept MSUs and place them on our own read queue.  If we are flow
 *  contolled, then we have no choice but to discard the message.  In
 *  addition, and because upstream message processing times are likely
 *  more sensitive to the number of backlogged messages than they are to
 *  the number of backlogged message octets, we have some configurable
 *  thresholds of backlogging and keep track of backlogged messages.
 *
 *  --------------------------------------------------------------------------
 */

static inline void sl_rb_congestion_function(sl_t *sl) 
{
    if ( !sl->statem.l3_congestion_detect ) {
        if ( sl->statem.l2_congestion_detect ) {
            if ( sl->statem.Cr <= sl->config.rb_abate && canputnext(sl->q) ) {
                sl_rc_no_congestion(sl);
                sl->statem.l2_congestion_detect = 0;
            }
        } else {
            if ( sl->statem.Cr >= sl->config.rb_discard || !canput(sl->q) ) {
                sl_rc_congestion_discard(sl);
                sl->statem.l2_congestion_detect = 1;
            } else
            if ( sl->statem.Cr >= sl->config.rb_accept || !canputnext(sl->q) ) {
                sl_rc_congestion_accept(sl);
                sl->statem.l2_congestion_detect = 1;
            }
        }
    }
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 6 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 6 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 4 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 8 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 8 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 5 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 10 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 10 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 6 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 14 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 14 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
static inline void sl_lsc_sio(sl_t *sl) 
{
    sl_timer_stop(t1);  /* ok if no running */
    sl->statem.failure_reason = SL_FAIL_RECEIVED_SIO;
    sl_l3_out_of_service(sl);
    sl_rc_stop(sl);
    sl_suerm_stop(sl);
    sl_eim_stop(sl);
    sl_poc_stop(sl);    /* ok if ANSI */
    sl_txc_send_sios(sl);
    sl->statem.emergency = 0;
    sl->statem.local_processor_outage = 0;
    sl->statem.remote_processor_outage = 0; /* ok if ITUT */
    sl->statem.lsc_state = SL_STATE_OUT_OF_SERVICE;
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 5 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 5 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 3 of 7) */
static inline void sl_lsc_alignment_not_possible(sl_t *sl) 
{
    sl->statem.failure_reason = SL_FAIL_ALIGNMENT_NOT_POSSIBLE;
    sl_l3_out_of_service(sl);
    sl_rc_stop(sl);
    sl_txc_send_sios(sl);
    sl->statem.local_processor_outage = 0;
    sl->statem.emergency = 0;
    sl->statem.lsc_state = SL_STATE_OUT_OF_SERVICE;
}

/* Inspected to Figure 9/Q.703 (03/93) (sheet 4 of 6) */
/* Inspected to Figure 9/T1.111.3-1992 (sheet 2 of 3) */
static void sl_t3_timeout(sl_t *sl) 
{
    if ( sl->statem.iac_state == SL_STATE_ALIGNED ) {
            sl_lsc_alignment_not_possible(sl);
            sl->statem.emergency = 0;
            sl->statem.iac_state = SL_STATE_IDLE;
    }
}

/* Inspected to Figure 17/Q.703 (03/93) */
/* Inspected to Figure 17/T1.111.3-1992 */
static inline void sl_aerm_start(sl_t *sl) 
{
    if ( sl->statem.aerm_state == SL_STATE_IDLE ) {
            sl->statem.Ca = 0;
            sl->statem.aerm_state = SL_STATE_MONITORING;
    }
}

/* Inspected to Figure 17/Q.703 (03/93) */
/* Inspected to Figure 17/T1.111.3-1992 */
static inline void sl_aerm_set_ti_to_tin(sl_t *sl) 
{
    if ( sl->statem.aerm_state == SL_STATE_IDLE ) {
        sl->statem.Ti = sl->config.Tin;
    }
}

/* Inspected to Figure 17/Q.703 (03/93) */
/* Inspected to Figure 17/T1.111.3-1992 */
static inline void sl_aerm_set_ti_to_tie(sl_t *sl) 
{
    if ( sl->statem.aerm_state == SL_STATE_IDLE ) {
        sl->statem.Ti = sl->config.Tie;
    }
}

/* Inspected to Figure 17/Q.703 (03/93) */
/* Inspected to Figure 17/T1.111.3-1992 */
static inline void sl_aerm_stop(sl_t *sl) 
{
    if ( sl->statem.aerm_state == SL_STATE_MONITORING ) {
            sl->statem.Ti = sl->config.Tin;
            sl->statem.aerm_state = SL_STATE_IDLE;
    }
}

static inline void sl_iac_sio(sl_t *sl) 
{
    switch ( sl->statem.iac_state ) {
        case SL_STATE_NOT_ALIGNED :
            /* Inspected to Figure 9/Q.703 (03/93) (sheet 2 of 6) */
            /* Inspected to Figure 9/T1.111.3-1992 (sheet 1 of 3) */
            sl_timer_stop(t2);
            if ( sl->statem.emergency ) {
                sl->statem.t4v = sl->config.t4e;
                sl_txc_send_sie(sl);
            } else {
                sl->statem.t4v = sl->config.t4n;
                sl_txc_send_sin(sl);
            }
            break;
        case SL_STATE_PROVING :
            /* Inspected to Figure 9/Q.703 (03/93) (sheet 5 of 6) */
            /* Inspected to Figure 9/T1.111.3-1992 (sheet 3 of 3) */
            sl_timer_stop(t4);
            sl_aerm_stop(sl);
            break;
    }
    sl_timer_start(t3);
    sl->statem.iac_state = SL_STATE_ALIGNED;
}

/* Inspected to Figure 9/Q.703 (03/93) (sheet 5 of 6) */
/* Inspected to Figure 9/T1.111.3-1992 (sheet 3 of 3) */
/* Inspected to Figure 9/Q.703 (03/93) (sheet 4 of 6) */
/* Inspected to Figure 9/T1.111.3-1992 (sheet 2 of 3) */
static inline void sl_iac_sios(sl_t *sl) 
{
    sl_timer_stop(t4);  /* ok if not running */
    sl_lsc_alignment_not_possible(sl);
    sl_aerm_stop(sl);   /* ok if not running */
    sl_timer_stop(t3);  /* ok if not running */
    sl->statem.emergency = 0;
    sl->statem.iac_state = SL_STATE_IDLE;
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 6 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 6 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 4 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 8 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 8 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 5 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 10 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 10 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 6 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 14 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 14 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
static inline void sl_lsc_sios(sl_t *sl) 
{
    sl_timer_stop(t1);  /* ok to stop if not running */
    sl->statem.failure_reason = SL_FAIL_RECEIVED_SIOS;
    sl_l3_out_of_service(sl);
    sl_suerm_stop(sl);  /* ok to stop if not running */
    sl_eim_stop(sl);
    sl_rc_stop(sl);
    sl_poc_stop(sl);    /* ok if ANSI */
    sl_txc_send_sios(sl);
    sl->statem.emergency = 0;
    sl->statem.local_processor_outage = 0;
    sl->statem.remote_processor_outage = 0; /* ok if ITU */
    sl->statem.lsc_state = SL_STATE_OUT_OF_SERVICE;
    return;
}

static inline void sl_lsc_fisu_msu_received(sl_t *sl) 
{
    switch (sl->statem.lsc_state ) {
        case SL_STATE_ALIGNED_READY :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 7 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 7 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 4 of 7) */
            sl_l3_in_service(sl);
            if ( sl->config.pvar == SL_PVAR_ITUT_93 )
                sl_rc_accept_msu_fisu(sl); /* unnecessary */
            sl_timer_stop(t1);
            sl_txc_send_msu(sl);
            sl->statem.lsc_state = SL_STATE_IN_SERVICE;
            return;
        case SL_STATE_ALIGNED_NOT_READY :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 9 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 9 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 5 of 7) */
            sl_l3_in_service(sl);
            sl_timer_stop(t1);
            sl->statem.lsc_state = SL_STATE_PROCESSOR_OUTAGE;
            return;
        case SL_STATE_PROCESSOR_OUTAGE :
            switch ( sl->config.pvar ) {
                case SS7_PVAR_ITUT_93:
                case SS7_PVAR_ITUT_96:
                    /* Inspected to Figure 8/Q.703 (03/93) (sheet 12 of 14) */
                    /* Inspected to Figure 8/Q.703 (07/96) (sheet 12 of 14) */
                    sl_poc_remote_processor_recovered(sl);
                    sl_l3_remote_processor_recovered(sl);
                    return;
                case SS7_PVAR_ANSI_92:
                    /* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
                    sl->statem.remote_processor_outage = 0;
                    sl_l3_remote_processor_recovered(sl);
                    return;
                default:
                    /*
                     *  A deviation from the SDLs has been
                     *  placed here to limit the number of
                     *  remote processor recovered
                     *  indications which are delivered to
                     *  L3.  One indication is sufficient.
                     */
                    if ( sl->statem.remote_processor_outage ) {
                        sl->statem.remote_processor_outage = 0;
                        sl_l3_remote_processor_recovered(sl);
                    }
                    return;
            }
    }
}
static inline void sl_lsc_sipo(sl_t *sl) 
{
    switch ( sl->statem.lsc_state ) {
        case SL_STATE_ALIGNED_READY :
            switch ( sl->config.pvar ) {
                case SS7_PVAR_ITUT_93:
                case SS7_PVAR_ITUT_96:
                    /* Inspected to Figure 8/Q.703 (03/93) (sheet 7 of 14) */
                    /* Inspected to Figure 8/Q.703 (07/96) (sheet 7 of 14) */
                    sl_timer_stop(t1);
                    sl_l3_remote_processor_outage(sl);
                    sl_poc_remote_processor_outage(sl);
                    sl->statem.lsc_state = SL_STATE_PROCESSOR_OUTAGE;
                    return;
                case SS7_PVAR_ANSI_92:
                    /* Inspected to Figure 8/T1.111.3-1992 (sheet 4 of 7) */
                    sl_timer_stop(t1);
                    sl_l3_remote_processor_outage(sl);
                    sl->statem.remote_processor_outage = 1;
                    sl->statem.lsc_state = SL_STATE_PROCESSOR_OUTAGE;
                    return;
            }
        case SL_STATE_ALIGNED_NOT_READY :
            switch ( sl->config.pvar ) {
                case SS7_PVAR_ITUT_93:
                case SS7_PVAR_ITUT_96:
                    /* Inspected to Figure 8/Q.703 (03/93) (sheet 9 of 14) */
                    /* Inspected to Figure 8/Q.703 (07/96) (sheet 9 of 14) */
                    sl_l3_remote_processor_outage(sl);
                    sl_poc_remote_processor_outage(sl);
                    sl_timer_stop(t1);
                    sl->statem.lsc_state = SL_STATE_PROCESSOR_OUTAGE;
                    return;
                case SS7_PVAR_ANSI_92:
                    /* Inspected to Figure 8/T1.111.3-1992 (sheet 5 of 7) */
                    sl_l3_remote_processor_outage(sl);
                    sl->statem.remote_processor_outage = 1;
                    sl_timer_stop(t1);
                    sl->statem.lsc_state = SL_STATE_PROCESSOR_OUTAGE;
                    return;
            }
        case SL_STATE_IN_SERVICE :
            switch ( sl->config.pvar ) {
                case SS7_PVAR_ITUT_93:
                case SS7_PVAR_ITUT_96:
                    /* Inspected to Figure 8/Q.703 (03/93) (sheet 11 of 14) */
                    /* Inspected to Figure 8/Q.703 (07/96) (sheet 11 of 14) */
                    sl_txc_send_fisu(sl);
                    sl_l3_remote_processor_outage(sl);
                    sl_poc_remote_processor_outage(sl);
                    sl->statem.processor_outage = 1; /* remote? */
                    sl->statem.lsc_state = SL_STATE_PROCESSOR_OUTAGE;
                    return;
                case SS7_PVAR_ANSI_92:
                    /* Inspected to Figure 8/T1.111.3-1992 (sheet 6 of 7) */
                    sl_txc_send_fisu(sl);
                    sl_l3_remote_processor_outage(sl);
                    sl->statem.remote_processor_outage = 1;
                    sl_rc_align_fsnx(sl);
                    sl_cc_stop(sl);
                    sl->statem.lsc_state = SL_STATE_PROCESSOR_OUTAGE;
                    return;
            }
        case SL_STATE_PROCESSOR_OUTAGE :
            switch ( sl->config.pvar ) {
                case SS7_PVAR_ITUT_93:
                case SS7_PVAR_ITUT_96:
                    /* Inspected to Figure 8/Q.703 (03/93) (sheet 12 of 14) */
                    /* Inspected to Figure 8/Q.703 (07/96) (sheet 12 of 14) */
                    sl_l3_remote_processor_outage(sl);
                    sl_poc_remote_processor_outage(sl);
                    return;
                case SS7_PVAR_ANSI_92:
                    /* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
                    sl->statem.remote_processor_outage = 1;
                    sl_l3_remote_processor_outage(sl);
                    return;
                default:
                    /*
                     *  A deviation from the SDLs has been
                     *  placed here to limit the number of
                     *  remote processor outage indications
                     *  which are delivered to L3.  One
                     *  indication is sufficient.
                     */
                    if ( !sl->statem.remote_processor_outage ) {
                        sl->statem.remote_processor_outage = 1;
                        sl_l3_remote_processor_outage(sl);
                    }
                    return;
            }
    }
}

/* Inspected to Figure 9/Q.703 (03/93) (sheet 1 of 6) */
/* Inspected to Figure 9/T1.111.3-1992 (sheet 1 of 3) */
static void sl_t2_timeout(sl_t *sl) 
{
    if ( sl->statem.iac_state == SL_STATE_NOT_ALIGNED ) {
            sl_lsc_alignment_not_possible(sl);
            sl->statem.emergency = 0;
            sl->statem.iac_state = SL_STATE_IDLE;
    }
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 6 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 4 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 8 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 5 of 7) */
static void sl_t1_timeout(sl_t *sl) 
{
    sl->statem.failure_reason = SL_FAIL_T1_TIMEOUT;
    sl_l3_out_of_service(sl);
    sl_rc_stop(sl);
    sl_suerm_stop(sl);
    sl_eim_stop(sl);
    sl_txc_send_sios(sl);
    sl->statem.emergency = 0;
    if ( sl->statem.lsc_state == SL_STATE_ALIGNED_NOT_READY ) {
        sl_poc_stop(sl);        /* ok if ANSI */
        sl->statem.local_processor_outage = 0;
    }
    sl->statem.lsc_state = SL_STATE_OUT_OF_SERVICE;
}

/* Inspected to Figure 18/Q.703 (03/93) */
/* Inspected to Figure 18/T1.111.3-1992 */
static inline void sl_suerm_start(sl_t *sl) 
{
    sl->statem.Cs = 0;
    sl->statem.Ns = 0;
    sl->statem.suerm_state = SL_STATE_IN_SERVICE;
}

static void sl_t8_timeout(sl_t *sl)
{
    if ( sl->statem.eim_state == SL_STATE_MONITORING ) {
        sl_timer_start(t8);
        if (sl->statem.su_received) {
            sl->statem.su_received = 0;
            if ( !sl->statem.interval_error ) {
                if ( (sl->statem.Ce =- sl->statem.De) < 0 )
                    sl->statem.Ce = 0;
                return;
            }
        }
        sl->statem.Ce += sl->statem.Ue;
        sl->statem.interval_error = 0;
        if ( sl->statem.Ce > sl->statem.Te ) {
            sl_lsc_link_failure(sl, SL_FAIL_SUERM_EIM);
            sl->statem.eim_state = SL_STATE_IDLE;
        }
    }
}

static inline void sl_eim_start(sl_t *sl)
{
    if ( sl->statem.eim_state == SL_STATE_IDLE ) {
        sl->statem.Ce = 0;
        sl->statem.interval_monitor = 0;
        sl->statem.su_received = 0;
        sl_timer_start(t8);
        sl->statem.eim_state = SL_STATE_MONITORING;
    }
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 5 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 5 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 3 of 7) */
static inline void sl_lsc_alignment_complete(sl_t *sl) 
{
    if ( sl->statem.lsc_state == SL_STATE_INITIAL_ALIGNMENT ) {
        if ( sl->config.popt & SL_POPT_HSL )
            sl_eim_start(sl); else sl_suerm_start(sl);
        sl_timer_start(t1);
        if ( sl->statem.local_processor_outage ) {
            if ( sl->config.pvar != SS7_PVAR_ANSI_92 )
                sl_poc_local_processor_outage(sl);
            sl_txc_send_sipo(sl);
            if ( sl->config.pvar != SS7_PVAR_ITUT_93 )  /* possible error */
            sl_rc_reject_msu_fisu(sl);
            sl->statem.lsc_state = SL_STATE_ALIGNED_NOT_READY;
        } else {
            sl_txc_send_fisu(sl);
            sl_rc_accept_msu_fisu(sl); /* error in ANSI spec? */
            sl->statem.lsc_state = SL_STATE_ALIGNED_READY;
        }
    }
}

/* Inspected to Figure 9/Q.703 (03/93) (sheet 5 of 6) */
/* Inspected to Figure 9/T1.111.3-1992 (sheet 3 of 3) */
static void sl_t4_timeout(sl_t *sl) 
{
    switch ( sl->statem.iac_state == SL_STATE_PROVING ) {
        if ( sl->statem.further_proving ) {
            sl_aerm_start(sl);
            sl->statem.further_proving = 0;
            sl_timer_start_t4(t4v);
        } else {
            sl_lsc_alignment_complete(sl);
            sl_aerm_stop(sl);
            sl->statem.emergency = 0;
            sl->statem.iac_state = SL_STATE_IDLE;
        }
    }
}

static inline void sl_lsc_sin(sl_t *sl) 
{
    switch ( sl->statem.lsc_state ) {
        case SL_STATE_IN_SERVICE :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 10 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 10 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 6 of 7) */
            sl->statem.failure_reason = SL_FAIL_RECEIVED_SIN;
            sl_l3_out_of_service(sl);
            sl_suerm_stop(sl);
            sl_eim_stop(sl);
            sl_rc_stop(sl);
            sl_txc_send_sios(sl);
            sl->statem.emergency = 0;
            sl->statem.lsc_state = SL_STATE_OUT_OF_SERVICE;
            return;
        case SL_STATE_PROCESSOR_OUTAGE :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 14 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 14 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
            sl->statem.failure_reason = SL_FAIL_RECEIVED_SIN;
            sl_l3_out_of_service(sl);
            sl_suerm_stop(sl);
            sl_eim_stop(sl);
            sl_rc_stop(sl);
            sl_poc_stop(sl);                        /* ok if not ITUT */
            sl_txc_send_sios(sl);
            sl->statem.emergency = 0;
            sl->statem.local_processor_outage = 0;
            sl->statem.remote_processor_outage = 0; /* ok if not ANSI */
            sl->statem.lsc_state = SL_STATE_OUT_OF_SERVICE;
            return;
    }
}

static inline void sl_iac_sin(sl_t *sl) 
{
    switch ( sl->statem.iac_state ) {
        case SL_STATE_NOT_ALIGNED :
            /* Inspected to Figure 9/Q.703 (03/93) (sheet 2 of 6) */
            /* Inspected to Figure 9/T1.111.3-1992 (sheet 1 of 3) */
            sl_timer_stop(t2);
            if ( sl->statem.emergency ) {
                sl->statem.t4v = sl->config.t4e;
                sl_txc_send_sie(sl);
            } else {
                sl->statem.t4v = sl->config.t4n;
                sl_txc_send_sin(sl);
            }
            sl_timer_start(t3);
            sl->statem.iac_state = SL_STATE_ALIGNED;
            return;
        case SL_STATE_ALIGNED :
            /* Inspected to Figure 9/Q.703 (03/93) (sheet 3 of 6) */
            /* Inspected to Figure 9/T1.111.3-1992 (sheet 2 of 3) */
            sl_timer_stop(t3);
            if ( sl->statem.t4v == sl->config.t4e )
                sl_aerm_set_ti_to_tie(sl);
            sl_aerm_start(sl);
            sl_timer_start_t4(t4v);
            sl->statem.Cp = 0;
            sl->statem.further_proving = 0;
            sl->statem.iac_state = SL_STATE_PROVING;
            return;
    }
}

static inline void sl_lsc_sie(sl_t *sl) 
{
    switch ( sl->statem.lsc_state ) {
        case SL_STATE_IN_SERVICE :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 10 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 10 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 6 of 7) */
            sl->statem.failure_reason = SL_FAIL_RECEIVED_SIE;
            sl_l3_out_of_service(sl);
            sl_suerm_stop(sl);
            sl_eim_stop(sl);
            sl_rc_stop(sl);
            sl_txc_send_sios(sl);
            sl->statem.emergency = 0;
            sl->statem.lsc_state = SL_STATE_OUT_OF_SERVICE;
            return;
        case SL_STATE_PROCESSOR_OUTAGE :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 14 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 14 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
            sl->statem.failure_reason = SL_FAIL_RECEIVED_SIE;
            sl_l3_out_of_service(sl);
            sl_suerm_stop(sl);
            sl_eim_stop(sl);
            sl_rc_stop(sl);
            sl_poc_stop(sl);                            /* ok if not ITUT */
            sl_txc_send_sios(sl);
            sl->statem.emergency = 0;
            sl->statem.local_processor_outage = 0;
            sl->statem.remote_processor_outage = 0;     /* ok if not ANSI */
            sl->statem.lsc_state = SL_STATE_OUT_OF_SERVICE;
            return;
    }
}

static inline void sl_iac_sie(sl_t *sl) 
{
    switch ( sl->statem.iac_state ) {
        case SL_STATE_NOT_ALIGNED :
            /* Inspected to Figure 9/Q.703 (03/93) (sheet 2 of 6) */
            /* Inspected to Figure 9/T1.111.3-1992 (sheet 1 of 3) */
            sl_timer_stop(t2);
            if ( sl->statem.emergency ) {
                sl->statem.t4v = sl->config.t4e;
                sl_txc_send_sie(sl);
            } else {
                sl->statem.t4v = sl->config.t4e; /* yes e */
                sl_txc_send_sin(sl);
            }
            sl_timer_start(t3);
            sl->statem.iac_state = SL_STATE_ALIGNED;
            return;
        case SL_STATE_ALIGNED :
            /* Inspected to Figure 9/Q.703 (03/93) (sheet 3 of 6) */
            /* Inspected to Figure 9/T1.111.3-1992 (sheet 2 of 3) */
            sl->statem.t4v = sl->config.t4e;
            sl_timer_stop(t3);
            sl_aerm_set_ti_to_tie(sl);
            sl_aerm_start(sl);
            sl_timer_start_t4(t4v);
            sl->statem.Cp = 0;
            sl->statem.further_proving = 0;
            sl->statem.iac_state = SL_STATE_PROVING;
            return;
        case SL_STATE_PROVING :
            /* Inspected to Figure 9/Q.703 (03/93) (sheet 6 of 6) */
            /* Inspected to Figure 9/T1.111.3-1992 (sheet 3 of 3) */
            if ( sl->statem.t4v == sl->config.t4e )
                return;
            sl_timer_stop(t4);
            sl->statem.t4v = sl->config.t4e;
            sl_aerm_stop(sl);
            sl_aerm_set_ti_to_tie(sl);
            sl_aerm_start(sl);
            sl->statem.further_proving = 0;
            sl_timer_start_t4(t4v);
            return;
    }
}

static inline void sl_rc_signal_unit(sl_t *sl, mblk_t *mp) 
{
    /* Inspected to Figure 14/Q.703 (03/93) (sheet 2-5 of 7) */
    /* Inspected to Figure 16/Q.703 (03/93) (sheet 2-4 of 6) */
    /* Inspected to Figure 16/T1.111.3-1992 (sheet 2 of 3) */
    if ( sl->statem.rc_state != SL_STATE_IN_SERVICE ) { freemsg(mp); return; }
    if ( ((sl->statem.rx.len )==1)||((sl->statem.rx.len )==2) ) {
        switch ( sl->statem.rx.sio ) {
            case LSSU_SIO : { sl_lsc_sio (sl); sl_iac_sio (sl); break; }
            case LSSU_SIN : { sl_lsc_sin (sl); sl_iac_sin (sl); break; }
            case LSSU_SIE : { sl_lsc_sie (sl); sl_iac_sie (sl); break; }
            case LSSU_SIOS: { sl_lsc_sios(sl); sl_iac_sios(sl); break; }
            case LSSU_SIPO: { sl_lsc_sipo(sl);                  break; }
            case LSSU_SIB : { sl_txc_sib_received(sl);          break; }
        }
        freemsg(mp);
        return;
    }
    if ( SN_OUTSIDE((sl->statem.rx.F.fsn-1)&sl->statem.sn_mask, sl->statem.rx.R.bsn, sl->statem.rx.T.fsn) ) {
        freemsg(mp);
        if ( sl->statem.abnormal_bsnr ) {
            sl->statem.failure_reason = SL_FAIL_ABNORMAL_BSNR;
            sl_lsc_link_failure(sl);
            sl->statem.rc_state = SL_STATE_IDLE;
            freemsg(mp);
            return;
        } else {
            sl->statem.abnormal_bsnr = 1;
            sl->statem.unb = 0;
            freemsg(mp);
            return;
        }
    }
    if ( sl->statem.abnormal_bsnr ) {
        if ( sl->statem.unb == 1 ) {
            sl->statem.abnormal_bsnr = 0;
        } else {
            sl->statem.unb = 1;
            freemsg(mp);
            return;
        }
    }
    if ( sl->config.popt & SL_POPT_PCR ) {
        sl_lsc_fisu_msu_received(sl);
        sl_txc_bsnr_and_bibr(sl);
        sl->statem.rx.F.fsn = (sl->statem.rx.R.bsn +1)&sl->statem.sn_mask;
        if ( ! sl->statem.msu_fisu_accepted ) {
            freemsg(mp);
            return;
        }
        sl_rb_congestion_function(sl);
        if ( sl->statem.congestion_discard ) {
            freemsg(mp);
            sl_cc_busy(sl);
            return;
        }
        if ( (sl->statem.rx.R.fsn == sl->statem.rx.X.fsn ) && (sl->statem.rx.len > 2) ) {
            sl_l3_pdu(sl, mp);
            sl->statem.rx.X.fsn = (sl->statem.rx.X.fsn +1)&sl->statem.sn_mask;
            if ( sl->statem.congestion_accept )
                sl_cc_busy(sl);
            else sl_txc_fsnx_value(sl);
            return;
        } else {
            freemsg(mp);
            return;
        }
    }
    if ( sl->statem.rx.R.fib == sl->statem.rx.X.fib ) {
        if ( sl->statem.abnormal_fibr ) {
            if ( sl->statem.unf == 1 ) {
                sl->statem.abnormal_fibr = 0;
            } else {
                sl->statem.unf = 1;
                freemsg(mp);
                return;
            }
        }

        sl_lsc_fisu_msu_received(sl);
        sl_txc_bsnr_and_bibr(sl);
        sl->statem.rx.F.fsn = (sl->statem.rx.R.bsn +1)&sl->statem.sn_mask;
        if ( ! sl->statem.msu_fisu_accepted ) {
            freemsg(mp);
            return;
        }
        sl_rb_congestion_function(sl);
        if ( sl->statem.congestion_discard ) {
            sl->statem.rtr = 1;
            freemsg(mp);
            sl_cc_busy(sl);
            return;
        }
        if ( (sl->statem.rx.R.fsn == sl->statem.rx.X.fsn ) && (sl->statem.rx.len > 2) ) {
            sl->statem.rx.X.fsn = (sl->statem.rx.X.fsn +1)&sl->statem.sn_mask;
            sl->statem.rtr = 0;
            sl_l3_pdu(sl, mp);
            if ( sl->statem.congestion_accept )
                 sl_cc_busy(sl);
            else sl_txc_fsnx_value(sl);
            return;
        }
        if ( (sl->statem.rx.R.fsn == ((sl->statem.rx.X.fsn -1)&sl->statem.sn_mask)) ) {
            freemsg(mp);
            return;
        } else {

            if ( sl->statem.congestion_accept ) {
                sl->statem.rtr = 1;
                sl_cc_busy(sl); /* not required? */
                freemsg(mp);
                return;
            } else {
                sl_txc_nack_to_be_sent(sl);
                sl->statem.rtr = 1;
                sl->statem.rx.X.fib = sl->statem.rx.X.fib ?0:sl->statem.ib_mask;
                freemsg(mp);
                return;
            }
        }
    } else {
        freemsg(mp);
        if ( sl->statem.abnormal_fibr ) {
            sl->statem.failure_reason = SL_FAIL_ABNORMAL_FIBR;
            sl_lsc_link_failure(sl);
            return;
        }
        if ( sl->statem.rtr == 1 ) {
            sl_txc_bsnr_and_bibr(sl);
            sl->statem.rx.F.fsn = (sl->statem.rx.R.bsn +1)&sl->statem.sn_mask;
            return;
        }
        sl->statem.abnormal_fibr = 1;
        sl->statem.unf = 0;
        return;
    }
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 5 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 5 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 3 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 6 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 6 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 4 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 8 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 8 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 5 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 10 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 10 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 6 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 14 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 14 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
static void sl_lsc_stop(sl_t *sl, mblk_t *mp) 
{
    (void)mp;
    if ( sl->statem.lsc_state != SL_STATE_OUT_OF_SERVICE ) {
        sl_iac_stop(sl);    /* ok if not running */
        sl_timer_stop(t1);  /* ok if not running */
        sl_rc_stop(sl);
        sl_suerm_stop(sl);  /* ok if not running */
        sl_eim_stop(sl);    /* ok if not running */
        sl_poc_stop(sl);    /* ok if not running or not ITUT */
        sl_txc_send_sios(sl);
        sl->statem.emergency = 0;
        sl->statem.local_processor_outage = 0;
        sl->statem.remote_processor_outage = 0;     /* ok of not ANSI */
        sl->statem.lsc_state = SL_STATE_OUT_OF_SERVICE;
    }
}

/* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
static inline void sl_lsc_clear_rtb(sl_t *sl) 
{
    if ( sl->statem.lsc_state == SL_STATE_PROCESSOR_OUTAGE ) {
        sl->statem.local_processor_outage = 0;
        sl_txc_send_fisu(sl);
        sl_txc_clear_rtb(sl);
    }
}

/* Inspected to Figure 9/Q.703 (03/93) (sheet 5 of 6) */
/* Inspected to Figure 9/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_iac_correct_su(sl_t *sl) 
{
    if ( sl->statem.iac_state == SL_STATE_PROVING ) {
        if ( sl->statem.further_proving ) {
            sl_timer_stop(t4);
            sl_aerm_start(sl);
            sl->statem.further_proving = 0;
            sl_timer_start_t4(t4v);
        }
    }
}

/* Inspected to Figure 9/Q.703 (03/93) (sheet 6 of 6) */
/* Inspected to Figure 9/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_iac_abort_proving(sl_t *sl) 
{
    if ( sl->statem.iac_state == SL_STATE_PROVING ) {
        sl->statem.Cp ++;
        if ( sl->statem.Cp == sl->config.M ) {
            sl_lsc_alignment_not_possible(sl);
            sl_timer_stop(t4);
            sl_aerm_stop(sl);
            sl->statem.emergency = 0;
            sl->statem.iac_state = SL_STATE_IDLE;
            return;
        }
        sl->statem.further_proving = 1;
    }
}

/* Inspected to Figure 17/Q.703 (03/93) */
/* Inspected to Figure 17/T1.111.3-1992 */
static inline void sl_aerm_su_in_error(sl_t *sl) 
{
    if ( sl->statem.aerm_state == SL_STATE_MONITORING:) {
        sl->statem.Ca++;
        if ( sl->statem.Ca == sl->statem.Ti ) {
            sl_iac_abort_proving(sl);
            sl->statem.aerm_state = SL_STATE_IDLE;
        }
    }
}

/* Inspected to Figure 18/Q.703 (03/93) */
/* Inspected to Figure 18/T1.111.3-1992 */
static inline void sl_suerm_su_in_error(sl_t *sl) 
{
    if ( sl->statem.suerm_state == SL_STATE_IN_SERVICE ) {
        sl->statem.Cs++;
        if ( sl->statem.Cs == sl->config.T ) {
            sl->statem.failure_reason = SL_FAIL_SUERM_EIM;
            sl_lsc_link_failure(sl);
            sl->statem.suerm_state = SL_STATE_IDLE;
            return;
        }
        if ( sl->statem.Cs ) {
            sl->statem.Ns++;
            if ( sl->statem.Ns == sl->config.D ) {
                sl->statem.Cs--;
                sl->statem.Ns = 0;
            }
        }
    }
}

/* Inspected to Figure 18/Q.703 (03/93) */
/* Inspected to Figure 18/T1.111.3-1992 */
static inline void sl_suerm_correct_su(sl_t *sl) 
{
    if ( sl->statem.suerm_state == SL_STATE_IN_SERVICE ) {
        if ( sl->statem.Cs ) {
            sl->statem.Ns++;
            if ( sl->statem.Ns == sl->config.D ) {
                sl->statem.Cs--;
                sl->statem.Ns = 0;
            }
        }
    }
}

static inline void sl_eim_su_in_error(sl_t *sl)
{
    if ( sl->statem.eim_state == SL_STATE_MONITORING )
        sl->statem.interval_error = 1;
}

static inline void sl_eim_correct_su(sl_t *sl)
{
    if (sl->statem.eim_state == SL_STATE_MONITORING )
        sl->statem.su_received = 1;
}

/*
 *  When we are in octet counting mode we have to generate an error to
 *  the SUERM/AERM every N octets from the line.  At 64,000 bps, this is
 *  every 2 ms.  Unfortunately, DKI timers are only accurate to one tick
 *  (10ms).  Therefore, the SS7 device (which has a finer timing source)
 *  will have to generate the pulses to use after being told to start
 *  octet counting.
 */

/* Inspected to Figure 11/Q.703 (03/93) (sheet 1 of 2) */
/* Inspected to Figure 11/T1.111.3-1992 */
static inline void sl_daedr_N_octets(sl_t *sl) 
{
    if ( sl->statem.daedr_state == SL_STATE_IN_SERVICE ) {
        while (sl->statem.octets_counted ) { /* catch up algorithm */
            sl->statem.octets_counted --;
            if ( sl->statem.octet_counting_mode ) {
                sl_suerm_su_in_error(sl);
                sl_aerm_su_in_error(sl);
            }
        }
    } else sl->statem.octets_counted = 0;
}

/* Inspected to Figure 11/Q.703 (03/93) (sheet 1 of 2) */
/* Inspected to Figure 11/T1.111.3-1992 */
static inline void sl_daedr_loss_of_sync(sl_t *sl) 
{
    sl->statem.octet_counting_mode = 1;
}

/* Inspected to Figure 11/Q.703 (03/93) (sheet 1 of 2) */
/* Inspected to Figure 11/T1.111.3-1992 */
static inline void sl_daedr_error_frame(sl_t *sl) 
{
    if ( sl->statem.daedr_state == SL_STATE_IN_SERVICE ) {
        if ( !sl->statem.octet_counting_mode ) {
            sl_suerm_su_in_error(sl);
            sl_aerm_su_in_error(sl);
        }
    }
}

static inline void sl_daedr_compressed_frame(sl_t *sl) 
{
    /* Inspected to Figure 11/Q.703 (03/93) (sheet 2 of 2) */
    /* Inspected to Figure 11/T1.111.3-1992 */
    if ( sl->statem.daedr_state == SL_STATE_IN_SERVICE ) {
        while (sl->statem.sus_repeated ) {  /* catch up algorithm */
            sl->statem.sus_repeated--;
            sl_iac_correct_su(sl);
            sl_suerm_correct_su(sl);
        }
    } else sl->statem.sus_repeated = 0;
}

/* Inspected to Figure 11/Q.703 (03/93) (sheet 2 of 2) */
/* Inspected to Figure 11/T1.111.3-1992 */
static inline void sl_daedr_received_frame(sl_t *sl, mblk_t *mp) 
{
    /*
     *  Note: the driver must check that the length of the frame is
     *  within appropriate bounds as specified by the DAEDR in Q.703.
     *  If the length of the frame is incorrect, it should indicate
     *  daedr_error_frame rather than daedr_received_frame.
     */
    if ( sl->statem.daedr_state == SL_STATE_IN_SERVICE ) {
        sl->statem.octet_counting_mode = 0;
        if ( sl->config.popt & SL_POPT_XSN ) {
            sl->statem.rx.R.bsn = *((sl_ushort *)mp->b_rptr) & 0x0fff;
            sl->statem.rx.R.bib = *((sl_ushort *)mp->b_rptr) & 0x8000;
            mp->b_rptr += 2;
            sl->statem.rx.R.fsn = *((sl_ushort *)mp->b_rptr) & 0x0fff;
            sl->statem.rx.R.fib = *((sl_ushort *)mp->b_rptr) & 0x8000;
            mp->b_rptr += 2;
            sl->statem.rx.len   = *((sl_ushort *)mp->b_rptr) & 0x01ff;
            mp->b_rptr += 2;
            sl->statem.rx.sio   = *mp->b_rptr++ & 0x07;
        } else {
            sl->statem.rx.R.bsn = *mp->b_rptr   & 0x7f;
            sl->statem.rx.R.bib = *mp->b_rptr++ & 0x80;
            sl->statem.rx.R.fsn = *mp->b_rptr   & 0x7f;
            sl->statem.rx.R.fib = *mp->b_rptr++ & 0x80;
            sl->statem.rx.len   = *mp->b_rptr++ & 0x3f;
            sl->statem.rx.sio   = *mp->b_rptr++ & 0x07;
        }
        sl_rc_signal_unit(sl, mp);
        sl_iac_correct_su(sl);
        sl_suerm_correct_su(sl);
    } else {
        sl->statem.octet_counting_mode = 0;
        freemsg(mp);
    }
}

#define sl_lsc_flush_buffers sl_lsc_clear_buffers
static void sl_lsc_clear_buffers(sl_t *sl, mblk_t *mp) 
{
    (void)mp;
    switch ( sl->statem.lsc_state ) {
        case SL_STATE_OUT_OF_SERVICE :
            switch ( sl->config.pvar ) {
                case SS7_PVAR_ITUT_93:
                case SS7_PVAR_ITUT_96:
                    /* Inspected to Figure 8/Q.703 (03/93) (sheet 2 of 14) */
                    /* Inspected to Figure 8/Q.703 (07/96) (sheet 2 of 14) */
                    return;
                case SS7_PVAR_ANSI_92:
                    /* Inspected to Figure 8/T1.111.3-1992 (sheet 2 of 7) */
                    sl_l3_rtb_cleared(sl);
                    sl->statem.local_processor_outage = 0; /* ??? */
                    return;
            }
        case SL_STATE_INITIAL_ALIGNMENT :
            switch ( sl->config.pvar ) {
                case SS7_PVAR_ITUT_93:
                case SS7_PVAR_ITUT_96:
                    /* Inspected to Figure 8/Q.703 (03/93) (sheet 4 and 5 of 14) */
                    /* Inspected to Figure 8/Q.703 (07/96) (sheet 4 and 5 of 14) */
                    return;
                case SS7_PVAR_ANSI_92:
                    /* Inspected to Figure 8/T1.111.3-1992 (sheet 3 of 7) */
                    sl_l3_rtb_cleared(sl);
                    sl->statem.local_processor_outage = 0;
                    return;
            }
        case SL_STATE_ALIGNED_NOT_READY :
            switch ( sl->config.pvar ) {
                case SS7_PVAR_ITUT_93:
                case SS7_PVAR_ITUT_96:
                    /* Inspected to Figure 8/Q.703 (03/93) (sheet 8 and 9 of 14) */
                    /* Inspected to Figure 8/Q.703 (07/96) (sheet 8 and 9 of 14) */
                    return;
                case SS7_PVAR_ANSI_92:
                    /* Inspected to Figure 8/T1.111.3-1992 (sheet 5 of 7) */
                    sl_l3_rtb_cleared(sl);
                    sl->statem.local_processor_outage = 0;
                    sl_txc_send_fisu(sl);
                    sl->statem.lsc_state = SL_STATE_ALIGNED_READY;
                    return;
            }
        case SL_STATE_PROCESSOR_OUTAGE :
            switch ( sl->config.pvar ) {
                case SS7_PVAR_ITUT_93:
                case SS7_PVAR_ITUT_96:
                    /* Inspected to Figure 8/Q.703 (03/93) (sheet 13 of 14) */
                    /* Inspected to Figure 8/Q.703 (07/96) (sheet 13 of 14) */
                    sl_txc_flush_buffers(sl);
                    sl->statem.l3_indication_received = 1;
                    if ( sl->statem.processor_outage )
                        return;
                    sl->statem.l3_indication_received = 0;
                    sl_txc_send_msu(sl);
                    sl->statem.local_processor_outage = 0;
                    sl_rc_accept_msu_fisu(sl);
                    sl->statem.lsc_state = SL_STATE_IN_SERVICE;
                    return;
                case SS7_PVAR_ANSI_92:
                    /* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
                    sl->statem.local_processor_outage = 0;
                    sl_rc_clear_rb(sl);
                    sl_rc_accept_msu_fisu(sl);
                    sl_txc_send_fisu(sl);
                    sl_txc_clear_tb(sl);
                    sl_txc_clear_rtb(sl);
                    return;
            }
    }
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 13 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 13 of 14) */
/* Not used in ANSI */
static void sl_lsc_continue(sl_t* sl, mblk_t *mp)
{
    if ( sl->statem.lsc_state == SL_STATE_PROCESSOR_OUTAGE ) {
        if ( sl->statem.processor_outage ) return;
        sl->statem.l3_indication_received = 0;
        sl_txc_send_msu(sl);
        sl->statem.local_processor_outage = 0;
        sl_rc_accept_msu_fisu(sl);
        sl->statem.lsc_state = SL_STATE_IN_SERVICE;
    }
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 13 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 13 of 14) */
/* Not used in ANSI */
static void sl_lsc_no_processor_outage(sl_t* sl, mblk_t *mp)
{
    if ( sl->stream.lsc_state == SL_STATE_PROCESSOR_OUTAGE ) {
        sl->statem.processor_outage = 0;
        if ( !sl->statem.l3_indication_received ) return;
        sl->statem.l3_indication_received = 0;
        sl_txc_send_msu(sl);
        sl->statem.local_processor_outage = 0;
        sl_rc_accept_msu_fisu(sl);
        sl->statem.lsc_state = SL_STATE_IN_SERVICE;
    }
}

/* Inspected to Figure 10/Q.703 (03/93) */
/* Not used in ANSI */
static void sl_poc_local_processor_outage(sl_t* sl)
{
    switch ( sl->stream.poc_state ) {
        case SL_STATE_IDLE:
            sl->statem.poc_state = SL_STATE_LOCAL_PROCESSOR_OUTAGE;
            return;
        case SL_STATE_REMOTE_PROCESSOR_OUTAGE:
            sl->statem.poc_state = SL_STATE_BOTH_PROCESSORS_OUT;
            return;
    }
}

/* Inspected to Figure 10/Q.703 (03/93) */
/* Not used in ANSI */
static void sl_poc_local_processor_recovered(sl_t* sl)
{
    switch ( sl->stream.poc_state ) {
        case SL_STATE_LOCAL_PROCESSOR_OUTAGE:
            sl_lsc_no_processor_outage(sl);
            sl->statem.poc_state = SL_STATE_IDLE;
            return;
        case SL_STATE_BOTH_PROCESSORS_OUT:
            sl->statem.poc_state = SL_STATE_REMOTE_PROCESSOR_OUTAGE;
            return;
    }
}

/* Inspected to Figure 10/Q.703 (03/93) */
/* Not used in ANSI */
static void sl_poc_remote_processor_outage(sl_t* sl)
{
    switch ( sl->stream.poc_state ) {
        case SL_STATE_IDLE:
            sl->statem.poc_state = SL_STATE_REMOTE_PROCESSOR_OUTAGE;
            return;
        case SL_STATE_LOCAL_PROCESSOR_OUTAGE:
            sl->statem.poc_state = SL_STATE_BOTH_PROCESSORS_OUT;
            return;
    }
}

/* Inspected to Figure 10/Q.703 (03/93) */
/* Not used in ANSI */
static void sl_poc_remote_processor_recovered(sl_t* sl)
{
    switch ( sl->stream.poc_state ) {
        case SL_STATE_REMOTE_PROCESSOR_OUTAGE:
            sl_lsc_no_processor_outage(sl);
            sl->statem.poc_state = SL_STATE_IDLE;
            return;
        case SL_STATE_BOTH_PROCESSORS_OUT:
            sl->statem.poc_state = SL_STATE_LOCAL_PROCESSOR_OUTAGE;
            return;
    }
}

static void sl_poc_stop(sl_t* sl)
{
    sl->statem.poc_state = SL_STATE_IDLE;
}

#define sl_lsc_resume sl_lsc_local_processor_recovered
static void sl_lsc_local_processor_recovered(sl_t *sl, mblk_t *mp) 
{
    (void)mp;
    switch ( sl->statem.lsc_state ) {
        case SL_STATE_OUT_OF_SERVICE :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 3 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 3 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 2 of 7) */
            sl->statem.local_processor_outage = 0;
            return;
        case SL_STATE_INITIAL_ALIGNMENT :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 4 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 4 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 3 of 7) */
            sl->statem.local_processor_outage = 0;
            return;
        case SL_STATE_ALIGNED_READY :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 6 and 7 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 6 and 7 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 4 of 7) */
            return;
        case SL_STATE_ALIGNED_NOT_READY :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 9 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 9 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 5 of 7) */
            if ( sl->config.pvar != SS7_PVAR_ANSI_92 )
                sl_poc_local_processor_recovered(sl);
            sl->statem.local_processor_outage = 0;
            sl_txc_send_fisu(sl);
            if ( sl->config.pvar == SS7_PVAR_ITUT_96 )
                sl_rc_accept_msu_fisu(sl);
            sl->statem.lsc_state = SL_STATE_ALIGNED_READY;
            return;
        case SL_STATE_PROCESSOR_OUTAGE :
            switch ( sl->config.pvar ) {
                case SS7_PVAR_ITUT_93:
                case SS7_PVAR_ITUT_96:
                    /* Inspected to Figure 8/Q.703 (03/93) (sheet 13 of 14) */
                    /* Inspected to Figure 8/Q.703 (07/96) (sheet 13 of 14) */
                    sl_poc_local_processor_recovered(sl);
                    sl_rc_retrieve_fsnx(sl);
                    sl_txc_send_fisu(sl); /* note 3: in fisu BSN <= FSNX-1 */
                    sl->statem.lsc_state = SL_STATE_IN_SERVICE;
                case SS7_PVAR_ANSI_92:
                    /* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
                    sl->statem.local_processor_outage = 0;
                    sl_rc_accept_msu_fisu(sl);
                    if ( sl->statem.remote_processor_outage ) {
                        sl_txc_send_fisu(sl);
                        sl_l3_remote_processor_outage(sl);
                        return;
                    }
                    sl_txc_send_msu(sl);
                    sl->statem.lsc_state = SL_STATE_IN_SERVICE;
                    return;
            }
    }
}

#define sl_lsc_level_3_failure sl_lsc_local_processor_outage
static void sl_lsc_local_processor_outage(sl_t *sl, mblk_t *mp) 
{
    (void)mp;
    switch ( sl->statem.lsc_state ) {
        case SL_STATE_OUT_OF_SERVICE :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 3 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 3 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 2 of 7) */
        case SL_STATE_INITIAL_ALIGNMENT :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 4 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 4 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 3 of 7) */
            sl->statem.local_processor_outage = 1;
            return;
        case SL_STATE_ALIGNED_READY :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 7 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 7 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 4 of 7) */
            if ( sl->config.pvar == SS7_PVAR_ANSI_92 )
                 sl->statem.local_processor_outage = 1;
            else sl_poc_local_processor_outage(sl);
            sl_txc_send_sipo(sl);
            if ( sl->config.pvar != SS7_PVAR_ITUT_93 ) /* possible error 93 specs */
                sl_rc_reject_msu_fisu(sl);
            sl->statem.lsc_state = SL_STATE_ALIGNED_NOT_READY;
            return;
        case SL_STATE_IN_SERVICE :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 11 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 11 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 6 of 7) */
            if ( sl->config.pvar == SS7_PVAR_ANSI_92 ) {
                sl->statem.local_processor_outage = 1;
            } else {
                sl_poc_local_processor_outage(sl);
                sl->statem.processor_outage = 1;
            }
            sl_txc_send_sipo(sl);
            sl_rc_reject_msu_fisu(sl);
            if ( sl->config.pvar == SS7_PVAR_ANSI_92 ) {
                sl_rc_align_fsnx(sl);
                sl_cc_stop(sl);
            }
            sl->statem.lsc_state = SL_STATE_PROCESSOR_OUTAGE;
            return;
        case SL_STATE_PROCESSOR_OUTAGE :
            /* Inspected to Figure 8/Q.703 (03/93) (sheet 12 of 14) */
            /* Inspected to Figure 8/Q.703 (07/96) (sheet 12 of 14) */
            /* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
            if ( sl->config.pvar == SS7_PVAR_ANSI_92 )
                sl->statem.local_processor_outage = 1;
            else
                sl_poc_local_processor_outage(sl);
            sl_txc_send_sipo(sl);
            return;
    }
}

static inline void sl_iac_emergency(sl_t *sl) 
{
    switch ( sl->statem.iac_state ) {
        case SL_STATE_PROVING :
            /* Inspected to Figure 9/Q.703 (03/93) (sheet 6 of 6) */
            /* Inspected to Figure 9/T1.111.3-1992 (sheet 3 of 3) */
            sl_txc_send_sie(sl);
            sl_timer_stop(t4);
            sl->statem.t4v = sl->config.t4e;
            sl_aerm_stop(sl);
            sl_aerm_set_ti_to_tie(sl);
            sl_aerm_start(sl);
            sl->statem.further_proving = 0;
            sl_timer_start_t4(t4v);
            return;
        case SL_STATE_ALIGNED :
            /* Inspected to Figure 9/Q.703 (03/93) (sheet 3 of 6) */
            /* Inspected to Figure 9/T1.111.3-1992 (sheet 2 of 3) */
            sl_txc_send_sie(sl);
            sl->statem.t4v = sl->config.t4e;
            return;
        case SL_STATE_IDLE:
            /* Inspected to Figure 9/Q.703 (03/93) (sheet 1 of 6) */
            /* Inspected to Figure 9/T1.111.3-1992 (sheet 1 of 3) */
        case SL_STATE_NOT_ALIGNED:
            /* Inspected to Figure 9/Q.703 (03/93) (sheet 2 of 6) */
            /* Inspected to Figure 9/T1.111.3-1992 (sheet 1 of 3) */
            sl->statem.emergency = 1;
    }
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 3 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 3 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 2 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 4 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 4 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 3 of 7) */
static void sl_lsc_emergency(sl_t *sl, mblk_t *mp)
{
    freemsg(mp);
    sl->statem.emergency = 1;
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 3 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 3 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 2 of 7) */
static void sl_lsc_emergency_ceases(sl_t *sl, mblk_t *mp)
{
    freemsg(mp);
    sl->statem.emergency = 0;
}

/* Inspected to Figure 9/Q.703 (03/93) (sheet 1 of 6) */
/* Inspected to Figure 9/T1.111.3-1992 (sheet 1 of 3) */
static inline void sl_iac_start(sl_t *sl) 
{
    if ( sl->statem.iac-state == SL_STATE_IDLE ) {
        sl_txc_send_sio(sl);
        sl_timer_start(t2);
        sl->statem.iac_state = SL_STATE_NOT_ALIGNED;
    }
}

/* Inspected to Figure 12/Q.703 (03/93) */
static inline void sl_daedt_start(sl_t *sl) 
{
    if ( sl->statem.daedt_state == SL_STATE_IDLE ) {
        sl->statem.daedt_state = SL_STATE_IN_SERVICE;
        /* FIXME: Call driver hook to start transmitters
         * which in turn may call sl_txc_transmission_request(sl);
         * */
    }
}

/* Inspected to Figure 12/Q.703 (03/93) */
static inline void sl_daedt_transmission_request(sl_t *sl) 
{
    if ( sl->statem.daedt_state == SL_STATE_IN_SERVICE ) {
        sl_txc_transmission_request(sl);
    }
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 1 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 1 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 1 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 1 of 3) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 13/Q.703 (03/93) (sheet 2 of 7) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 1 of 3) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 2 of 4) */
static inline void sl_txc_start(sl_t *sl) 
{
    sl->statem.forced_retransmission = 0;           /* ok if basic */
    sl->statem.sib_received = 0;
    sl->statem.rtb_full = 0;
    sl->statem.clear_rtb = 0;                       /* ok if ITU */
    if ( sl->config.pvar == SS7_PVAR_ANSI_92 ) {
        sl->statem.tx.sio = LSSU_SIOS;
        sl->statem.lssu_available = 1;
    }
    sl->statem.msu_inhibited = 0;
    sl->statem.tx.L.fsn = sl->statem.tx.N.fsn = sl->statem.sn_mask;
    sl->statem.tx.X.fsn = 0;
    sl->statem.tx.N.fib = sl->statem.tx.N.bib = sl->statem.ib_mask;
    sl->statem.tx.F.fsn = 0;
    sl->statem.Cm = 0;
    sl->statem.Z = 0; sl->statem.z_ptr = NULL;      /* ok if basic */
    if ( sl->statem.txc_state == SL_STATE_IDLE ) {
        if ( sl->config.pvar != SS7_PVAR_ANSI_92 )
            sl->statem.lssu_available = 0;
        sl_daedt_start(sl);
    }
    sl->statem.txc_state = SL_STATE_IN_SERVICE;
    return;
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 2 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 2 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 2 of 7) */
static void sl_lsc_start(sl_t *sl, mblk_t *mp) 
{
    freemsg(mp);
    switch ( sl->statem.lsc_state ) {
        case SL_STATE_OUT_OF_SERVICE:
            sl_rc_start(sl);
            sl_txc_start(sl); /* Note 2 */
            if ( sl->statem.emergency ) sl_iac_emergency(sl);
            sl_iac_start(sl);
            sl->statem.lsc_state = SL_STATE_INITIAL_ALIGNMENT;
    }
}
    /*
     *  Note 2: There is a difference here between ANSI_92 and
     *          ITUT_93/96 in that the transmitters in the ANSI_92 case
     *          may transmit one or two SIOSs before transmitting the
     *          first SIO of the initial alignment procedure.  ITUT will
     *          continue idling FISU or LSSU as before the start, then
     *          transmit the first SIO.  These are equivalent.  Because
     *          the LSC is in the OUT OF SERVICE state, the transmitters
     *          should be idling SIOS anyway.
     */

/* Inspected to Figure 8/Q.703 (03/93) (sheet 2 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 2 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 2 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 12 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 12 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
static void sl_lsc_retrieve_bsnt(sl_t *sl, mblk_t *mp) 
{
    (void)mp;
    switch ( sl->statem.lsc_state ) {
        case SL_STATE_OUT_OF_SERVICE:
        case SL_STATE_PROCESSOR_OUTAGE:
            sl_rc_retrieve_bsnt(sl);
    }
}

/* Inspected to Figure 8/Q.703 (03/93) (sheet 2 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 2 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 2 of 7) */
/* Inspected to Figure 8/Q.703 (03/93) (sheet 12 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 12 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 7 of 7) */
static void sl_lsc_retrieval_request_and_fsnc(sl_t *sl, mblk_t *mp) 
{
    switch ( sl->statem.lsc_state ) {
        case SL_STATE_OUT_OF_SERVICE:
        case SL_STATE_PROCESSOR_OUTAGE:
            sl_txc_retrieval_request_and_fsnc(sl, mp);
    }
}

/*
 *  This power-on sequence should only be performed once, regardless of
 *  how many times the device driver is opened or closed.  This
 *  initializes the transmitters to send SIOS and should never be
 *  changed hence.
 */

/* Inspected to Figure 8/Q.703 (03/93) (sheet 1 of 14) */
/* Inspected to Figure 8/Q.703 (07/96) (sheet 1 of 14) */
/* Inspected to Figure 8/T1.111.3-1992 (sheet 1 of 7) */
static void sl_lsc_power_on(sl_t *sl) 
{
    switch ( sl->statem.lsc_state ) {
        case SL_STATE_POWER_OFF:
            sl_txc_start(sl);           /* Note 3 */
            sl_txc_send_sios(sl);       /* not necessary for ANSI */
            sl_aerm_set_ti_to_tin(sl);
            sl->statem.local_processor_outage = 0;
            sl->statem.emergency = 0;
            sl->statem.lsc_state = SL_STATE_OUT_OF_SERVICE;
    }
}
    /*
     *  Note 3: There is a difference here between ANSI_92 and
     *          ITUT_93/96 in that the transmitters in the ITUT case may
     *          transmit one or two FISUs before transmitting SIOS on
     *          initial power-up.  ANSI will send SIOS on power-up.
     *          ANSI is the correct procedure as transmitters should
     *          always idle SIOS on power-up.
     */

/*
 *  The transmit congestion algorithm is an implementation dependent
 *  algorithm but is suggested as being based on TB and/or RTB buffer
 *  occupancy.  With STREAMS we can use octet count buffer occupancy
 *  over message count occupancy, because congestion in transmission is
 *  more related to octet count (because it determines transmission
 *  latency).
 *
 *  We check the total buffer occupancy and apply the necessary
 *  congestion control signal as per configured abatement, onset and
 *  discard thresholds.
 */
static inline void sl_check_congestion(sl_t *sl)
{
    unsigned int occupancy = sl->tb->q_count + sl->rtb->q_count;
    int old_cong_level = sl->statem.cong_level;
    int old_disc_level = sl->statem.disc_level;
    int multi = sl->config.popt & SL_POPT_MPLEV;

    switch (sl->statem.cong_level) {
        case 0:
            if ( occupancy >= sl->config.tb_onset_1 ) {
                sl->statem.cong_level = 1;
                if ( occupancy >= sl->config.tb_discd_1 ) {
                    sl->statem.disc_level = 1;
                    if ( !multi ) break;
                    if ( occupancy >= sl->config.tb_onset_2 ) {
                        sl->statem.cong_level = 2;
                        if ( occupancy >= sl->config.tb_discd_2 ) {
                            sl->statem.disc_level = 2;
                            if ( occupancy >= sl->config.tb_onset_3 ) {
                                sl->statem.cong_level = 3;
                                if ( occupancy >= sl->config.tb_discd_3 ) {
                                    sl->statem.disc_level = 3; } } } } } }
            break;
        case 1:
            if ( occupancy <  sl->config.tb_abate_1 ) {
                sl->statem.cong_level = 0;
                sl->statem.disc_level = 0; } 
            else {
            if ( !multi ) break;
            if ( occupancy >= sl->config.tb_onset_2 ) {
                sl->statem.cong_level = 2;
                if ( occupancy >= sl->config.tb_discd_2 ) {
                    sl->statem.disc_level = 2;
                    if ( occupancy >= sl->config.tb_onset_3 ) {
                        sl->statem.cong_level = 3;
                        if ( occupancy >= sl->config.tb_discd_3 ) {
                            sl->statem.disc_level = 3; } } } }
            break;
        case 2:
            if ( !multi ) {
                sl->statem.cong_level = 1;
                sl->statem.disc_level = 1;
                break;
            }
            if ( occupancy <  sl->config.tb_abate_2 ) {
                sl->statem.cong_level = 1;
                sl->statem.disc_level = 1;
                if ( occupancy <  sl->config.tb_abate_1 ) {
                    sl->statem.cong_level = 0;
                    sl->statem.disc_level = 0; } }
            else
            if ( occupancy >= sl->config.tb_onset_3 ) {
                sl->statem.cong_level = 3;
                if ( occupancy >= sl->config.tb_discd_3 ) {
                    sl->statem.disc_level = 3; } }
            break;
        case 3:
            if ( !multi ) {
                sl->statem.cong_level = 1;
                sl->statem.disc_level = 1;
                break;
            }
            if ( occupancy <  sl->config.tb_abate_3 ) {
                sl->statem.cong_level = 2;
                sl->statem.disc_level = 2;
                if ( occupancy <  sl->config.tb_abate_2 ) {
                    sl->statem.cong_level = 1;
                    sl->statem.disc_level = 1;
                    if ( occupancy <  sl->config.tb_abate_1 ) {
                        sl->statem.cong_level = 0;
                        sl->statem.disc_level = 0; } } }
            break;
    }
    if ( sl->statem.cong_level != old_cong_level
      || sl->statem.disc_level != old_disc_level ) {
        if ( sl->statem.cong_level < old_cong_level )
            sl_l3_link_congestion_ceased(sl);
        else {
            if ( sl->statem.cong_level > old_cong_level ) {
                if ( sl->notify.events & SL_EVT_CONGEST_ONSET_IND &&
                        !sl->stats.sl_cong_onset_ind[sl->statem.cong_level]++ ) {
                    sl_l3_link_congested_event(sl);
                    return;
                }
            } else {
                if ( sl->notify.events & SL_EVT_CONGEST_DISCD_IND &&
                        !sl->stats.sl_cong_discd_ind[sl->statem.disc_level]++ ) {
                    sl_l3_link_congested_event(sl);
                    return;
                }
            }
            sl_l3_link_congested(sl);
        }
    }
}

/* Inspected to Figure 13/Q.703 (03/93) (sheet 5 of 7) */
/* Inspected to Figure 15/Q.703 (03/93) (sheet 5 of 7) */
/* Inspected to Figure 13/T1.111.3-1992 (sheet 3 of 4) */
/* Inspected to Figure 15/T1.111.3-1992 (sheet 3 of 3) */
static inline void sl_txc_message_for_transmission(sl_t *sl, mblk_t *mp)
{
    putq(sl->tb, mp);
    sl->statem.Cm++;
    sl_check_congestion(sl); /* maybe should do in sl_tqput */
    sl_daedt_transmitter_wakeup(sl); /* maybe just enable the tb
                                        and wakeup xmitters in
                                        sl_tqsrv */
}

static void sl_lsc_pdu(sl_t *sl, mblk_t *mp)
{
    mblk_t *md;
    if (mp->m_datap->db_type != M_DATA) {
        md = unlink(mp);
        freemsg(mp);
    } else
        md = mp;
    sl_txc_message_for_transmission(sl, md);
}

static void (*sl_user_req_ops[])(sl_t *sl, mblk_t *mp)
{
    &sl_lsc_pdu,
    &sl_lsc_emergency,
    &sl_lsc_emergency_ceases,
    &sl_lsc_start,
    &sl_lsc_stop,
    &sl_lsc_retrieve_bsnt,
    &sl_lsc_retrieval_request_and_fsnc,
    &sl_lsc_resume,
    &sl_lsc_clear_buffers,
    &sl_lsc_local_processor_outage,
    &sl_lsc_congestion_discard,
    &sl_lsc_congestion_accept,
    &sl_lsc_no_congestion
};

inline void sl_user_req(sl_t *sl, mblk_t *mp)
{
    union SL_primitives *req = (union SL_primitives *)mp->b_rptr;
    sl_ulong cmd = req->sl_primitive;
    if ( cmd < SL_PDU_REQ || cmd > SL_DS_LAST ) {
        freemsg(mp);
        return;
    }
    (sl_user_req_ops[cmd - SL_PDU_REQ])(sl, mp);
}

static void (*sl_driver_ind_ops[])(sl_t *sl, mblk_t *mp)
{
    sl_daedr_received_frame,
    sl_daedr_loss_of_sync,
    sl_daedr_N_octets,
    sl_daedr_compressed_frame
};

int sl_output(struct sk_buff *skb, struct device *dev)
{
    struct ss7_iface *iface = dev-> dn_ptr;
    skb_queue_tail(&iface->writ_q,skb);
    ss7_sm_dispatch(&iface->tx_taskq,&sl_lsc_l3_primitive);
    return 0;
}
void sl_rx(struct sk_buff *skb)
{
    struct ss7_iface *iface = skb->dev-> dn_ptr;
    skb_queue_tail(&iface->read_q,skb);
    ss7_sm_dispatch(&iface->rx_taskq,&sl_daedr_received_frame);
}
void sl_los(struct device *dev)
{
    struct ss7_iface *iface = dev-> dn_ptr;
    ss7_sm_dispatch(&iface->rx_taskq,&sl_daedr_loss_of_sync);
}
void sl_err(struct device *dev)
{
    struct ss7_iface *iface = dev-> dn_ptr;
    if (!iface->Octet_Counting_Mode)
        ss7_sm_dispatch(&iface->rx_taskq,&sl_daedr_error_frame);
}
void sl_oct(struct device *dev)
{
    struct ss7_iface *iface = dev-> dn_ptr;
    if (iface->Octet_Counting_Mode) {
        iface->Octets_Counted++;
        ss7_sm_dispatch(&iface->rx_taskq,&sl_daedr_N_octets);
    }
}
void sl_rpt(struct device *dev)
{
    struct ss7_iface *iface = dev-> dn_ptr;
    iface->SUs_Repeated++;
    ss7_sm_dispatch(&iface->rx_taskq,&sl_daedr_compressed_frame);
}


/*
 *  Calls from Management:
 *
 *  sl_lsc_power_on
 *  sl_lsc_local_processor_outage
 *  sl_lsc_level_3_failure
 *
 *
 *
 */

/*
 *  Calls from driver:
 *
 *  sl_daedr_N_octets(sl_t *sl);
 *  sl_daedr_loss_of_sync(sl_t *sl);
 *  sl_daedr_error_frame(sl_t *sl);
 *  sl_daedr_compressed_frame(sl_t *sl);
 *  sl_daedr_received_frame(sl_t *sl);
 *
 */









