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

 @(#) $Id: sls_tlac.h,v 0.7.2.11 2001/02/03 05:48:54 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:54 $ by $Author: brian $

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

#ifndef __SLS_TLAC_H__
#define __SLS_TLAC_H__

/*
 *  Referenced functions.
 *
 *  This state machine accesses HMRT, routing, restart and management functions.
 */

static inline void lk_mgmt_tlac_inhibit_denied(lk_t *lk);
static inline void lk_mgmt_tlac_link_inhibited(lk_t *lk);
static inline void lk_mgmt_tlac_link_uninhibited(lk_t *lk);
static inline void lk_mgmt_tlac_uninhibit_not_possible(lk_t *lk);
static inline void lk_mgmt_tlac_uninhibiting_not_possible(lk_t *lk);

static inline void lk_tsrc_tlac_cancel_link_inhibited(lk_t *lk);
static inline void lk_tsrc_tlac_link_in_service_at_level_2(lk_t *lk);
static inline void lk_tsrc_tlac_link_inhibited(lk_t *lk);
static inline void lk_tsrc_tlac_local_inhibit_request(lk_t *lk);
static inline void lk_tsrc_tlac_remote_inhibit_request(lk_t *lk);
static inline void lk_tsrc_tlac_signalling_link_available(lk_t *lk);
static inline void lk_tsrc_tlac_signalling_link_unavailable(lk_t *lk);
static inline void lk_tsrc_tlac_uninhibit_request(lk_t *lk);

static inline void lk_tprc_tlac_signalling_link_unavailable(lk_t *lk);

/* link and linkset functions */

static inline void lk_hmrt_tlac_emergency_changeover_ack(lk_t *lk, mblk_t *mp);
static inline void lk_hmrt_tlac_force_uninhibit_signalling_link(lk_t *lk, mblk_t *mp);
static inline void lk_hmrt_tlac_inhibit_ack(lk_t *lk, mblk_t *mp);
static inline void lk_hmrt_tlac_inhibit_denied(lk_t *lk, mblk_t *mp);
static inline void lk_hmrt_tlac_inhibit_signalling_link(lk_t *lk, mblk_t *mp);
static inline void lk_hmrt_tlac_local_inhibit_test(lk_t *lk, mblk_t *mp);
static inline void lk_hmrt_tlac_remote_inhibit_test(lk_t *lk, mblk_t *mp);
static inline void lk_hmrt_tlac_uninhibit_ack(lk_t *lk, mblk_t *mp);
static inline void lk_hmrt_tlac_uninhibit_signalling_link(lk_t *lk, mblk_t *mp);

static inline void lk_lsac_tlac_changeover_order_received(lk_t *lk);
static inline void lk_lsac_tlac_continue(lk_t *lk);
static inline void lk_lsac_tlac_flush_buffers(lk_t *lk);
static inline void lk_lsac_tlac_local_processor_outage(lk_t *lk);
static inline void lk_lsac_tlac_local_processor_recovered(lk_t *lk);
static inline void lk_lsac_tlac_signalling_link_available(lk_t *lk);
static inline void lk_lsac_tlac_signalling_link_availabled(lk_t *lk);

static inline void lk_tcoc_tlac_changeover_order(lk_t *lk, int fsnc);
static inline void lk_tcoc_tlac_emergency_changeover_order(lk_t *lk);
static inline void lk_tcoc_tlac_signalling_link_available(lk_t *lk);
static inline void lk_tcoc_tlac_signalling_link_unavailable(lk_t *lk);

static inline void lk_tcbc_tlac_signalling_link_available(lk_t *lk);

/*
 *  Forward declarations.
 */

static inline void lk_t12_timeout(lk_t *lk);
static inline void lk_t13_timeout(lk_t *lk);
static inline void lk_t14_timeout(lk_t *lk);
static inline void lk_t22_timeout(lk_t *lk);
static inline void lk_t23_timeout(lk_t *lk);
static inline void lk_t24_timeout(lk_t *lk);

static inline void lk_tlac_mgmt_inhibit_signalling_link(lk_t *lk);          /* from MGMT */
static inline void lk_tlac_mgmt_uninhibit_signalling_link(lk_t *lk);        /* from MGMT */
static inline void lk_tlac_mgmt_local_processor_outage(lk_t *lk);           /* from MGMT */
static inline void lk_tlac_mgmt_local_processor_recovered(lk_t *lk);        /* from MGMT */

static inline void lk_tlac_tprc_restart_begins(lk_t *lk);                   /* from MTP */
static inline void lk_tlac_tprc_restart_ends(lk_t *lk);                     /* from MTP */
static inline void lk_tlac_tprc_stop_restart(lk_t *lk);                     /* from MTP */
static inline void lk_tlac_tsrc_adjacent_sp_restarted(lk_t *lk);            /* from MTP */
static inline void lk_tlac_tsrc_adjacent_sp_restarting(lk_t *lk);           /* from MTP */
static inline void lk_tlac_tsrc_local_inhibit_allowed(lk_t *lk);            /* from MTP */
static inline void lk_tlac_tsrc_local_inhibit_denied(lk_t *lk);             /* from MTP */
static inline void lk_tlac_tsrc_remote_inhibit_allowed(lk_t *lk);           /* from MTP */
static inline void lk_tlac_tsrc_remote_inhibit_denied(lk_t *lk);            /* from MTP */
static inline void lk_tlac_tsrc_uninhibiting_not_possible(lk_t *lk);        /* from MTP */
static inline void lk_tlac_tsrc_uninhibiting_possible(lk_t *lk);            /* from MTP */
static inline void lk_tlac_tsrc_uninhibit_signalling_link(lk_t *lk);        /* from MTP */

static inline void lk_tlac_hmdt_changeover_order(lk_t *lk, mblk_t *mp);                 /* from remote L3 */
static inline void lk_tlac_hmdt_emergency_changeover_order(lk_t *lk, mblk_t *mp);       /* from remote L3 */
static inline void lk_tlac_hmdt_force_uninhibit_signalling_link(lk_t *lk, mblk_t *mp);  /* from remote L3 */
static inline void lk_tlac_hmdt_inhibit_ack(lk_t *lk, mblk_t *mp);                      /* from remote L3 */
static inline void lk_tlac_hmdt_inhibit_denied(lk_t *lk, mblk_t *mp);                   /* from remote L3 */
static inline void lk_tlac_hmdt_inhibit_signalling_link(lk_t *lk, mblk_t *mp);          /* from remote L3 */
static inline void lk_tlac_hmdt_local_inhibit_test(lk_t *lk, mblk_t *mp);               /* from remote L3 */
static inline void lk_tlac_hmdt_remote_inhibit_test(lk_t *lk, mblk_t *mp);              /* from remote L3 */
static inline void lk_tlac_hmdt_uninhibit_ack(lk_t *lk, mblk_t *mp);                    /* from remote L3 */
static inline void lk_tlac_hmdt_uninhibit_signalling_link(lk_t *lk, mblk_t *mp);        /* from remote L3 */

static inline void lk_tlac_lsac_link_in_service_at_level_2(lk_t *lk);
static inline void lk_tlac_lsac_remote_processor_outage(lk_t *lk);
static inline void lk_tlac_lsac_remote_processor_recovered(lk_t *lk);
static inline void lk_tlac_lsac_signalling_link_failed(lk_t *lk);
static inline void lk_tlac_lsac_signalling_link_in_service(lk_t *lk);

static inline void lk_tlac_tcbc_changeback_terminated(lk_t *lk);

static inline void lk_tlac_tcoc_changeover_executed(lk_t *lk);
static inline void lk_tlac_tcoc_changeover_not_required(lk_t *lk);

/*
 *  Message buidling functions.
 */

static inline void lk_tlac_send_emergency_changeover_ack(lk_t *lk, mblk_t *mp)
{
    ls_t *ls;
    ls_prim_t *p;
    if ( !(mp = __msg_alloc(mp)) ) return;
    ls = lk->module;
    p = (ls_prim_t *)mp->b_rptr;
    p->primitive     = LS_MESSAGE_FOR_ROUTING_IND;
    p->sig.signal    = LS_SIGNAL_ECA;
    p->eca.mh.ni     = ls->config.ni;
    p->eca.mh.mp     = 0x3;
    p->eca.mh.si     = 0x0;
    p->eca.mh.rl.dpc = ls->config.apc;
    p->eca.mh.rl.opc = ls->config.lpc;
    p->eca.mh.rl.sls = lk->config.slc;  /* FIXME */
    p->eca.slc       = lk->config.slc;
    lk_hmrt_tlac_emergency_changeover_ack(lk, mp);
}

static inline void lk_tlac_send_force_uninhibit_signalling_link(lk_t *lk, mblk_t *mp)
{
    ls_t *ls;
    ls_prim_t *p;
    if ( !(mp = __msg_alloc(mp)) ) return;
    ls = lk->module;
    p = (ls_prim_t *)mp->b_rptr;
    p->primitive     = LS_MESSAGE_FOR_ROUTING_IND;
    p->sig.signal    = LS_SIGNAL_LFU;
    p->lfu.mh.ni     = ls->config.ni;
    p->lfu.mh.mp     = 0x3;
    p->lfu.mh.si     = 0x0;
    p->lfu.mh.rl.dpc = ls->config.apc;
    p->lfu.mh.rl.opc = ls->config.lpc;
    p->lfu.mh.rl.sls = lk->config.slc;  /* FIXME */
    p->lfu.slc       = lk->config.slc;
    lk_hmrt_tlac_force_uninhibit_signalling_link(lk, mp);
}

static inline void lk_tlac_send_inhibit_ack(lk_t *lk, mblk_t *mp)
{
    ls_t *ls;
    ls_prim_t *p;
    if ( !(mp = __msg_alloc(mp)) ) return;
    ls = lk->module;
    p = (ls_prim_t *)mp->b_rptr;
    p->primitive     = LS_MESSAGE_FOR_ROUTING_IND;
    p->sig.signal    = LS_SIGNAL_LIA;
    p->lia.mh.ni     = ls->config.ni;
    p->lia.mh.mp     = 0x3;
    p->lia.mh.si     = 0x0;
    p->lia.mh.rl.dpc = ls->config.apc;
    p->lia.mh.rl.opc = ls->config.lpc;
    p->lia.mh.rl.sls = lk->config.slc;  /* FIXME */
    p->lia.slc       = lk->config.slc;
    lk_hmrt_tlac_inhibit_ack(lk, mp);
}

static inline void lk_tlac_send_inhibit_denied(lk_t *lk, mblk_t *mp)
{
    ls_t *ls;
    ls_prim_t *p;
    if ( !(mp = __msg_alloc(mp)) ) return;
    ls = lk->module;
    p = (ls_prim_t *)mp->b_rptr;
    p->primitive     = LS_MESSAGE_FOR_ROUTING_IND;
    p->sig.signal    = LS_SIGNAL_LID;
    p->lid.mh.ni     = ls->config.ni;
    p->lid.mh.mp     = 0x3;
    p->lid.mh.si     = 0x0;
    p->lid.mh.rl.dpc = ls->config.apc;
    p->lid.mh.rl.opc = ls->config.lpc;
    p->lid.mh.rl.sls = lk->config.slc;  /* FIXME */
    p->lid.slc       = lk->config.slc;
    lk_hmrt_tlac_inhibit_denied(lk, mp);
}

static inline void lk_tlac_send_inhibit_signalling_link(lk_t *lk, mblk_t *mp)
{
    ls_t *ls;
    ls_prim_t *p;
    if ( !(mp = __msg_alloc(mp)) ) return;
    ls = lk->module;
    p = (ls_prim_t *)mp->b_rptr;
    p->primitive     = LS_MESSAGE_FOR_ROUTING_IND;
    p->sig.signal    = LS_SIGNAL_LIN;
    p->lin.mh.ni     = ls->config.ni;
    p->lin.mh.mp     = 0x3;
    p->lin.mh.si     = 0x0;
    p->lin.mh.rl.dpc = ls->config.apc;
    p->lin.mh.rl.opc = ls->config.lpc;
    p->lin.mh.rl.sls = lk->config.slc;  /* FIXME */
    p->lin.slc       = lk->config.slc;
    lk_hmrt_tlac_inhibit_signalling_link(lk, mp);
}

static inline void lk_tlac_send_local_inhibit_test(lk_t *lk, mblk_t *mp)
{
    ls_t *ls;
    ls_prim_t *p;
    if ( !(mp = __msg_alloc(mp)) ) return;
    ls = lk->module;
    p = (ls_prim_t *)mp->b_rptr;
    p->primitive     = LS_MESSAGE_FOR_ROUTING_IND;
    p->sig.signal    = LS_SIGNAL_LLI;
    p->lli.mh.ni     = ls->config.ni;
    p->lli.mh.mp     = 0x3;
    p->lli.mh.si     = 0x0;
    p->lli.mh.rl.dpc = ls->config.apc;
    p->lli.mh.rl.opc = ls->config.lpc;
    p->lli.mh.rl.sls = lk->config.slc;  /* FIXME */
    p->lli.slc       = lk->config.slc;
    lk_hmrt_tlac_local_inhibit_test(lk, mp);
}

static inline void lk_tlac_send_remote_inhibit_test(lk_t *lk, mblk_t *mp)
{
    ls_t *ls;
    ls_prim_t *p;
    if ( !(mp = __msg_alloc(mp)) ) return;
    ls = lk->module;
    p = (ls_prim_t *)mp->b_rptr;
    p->primitive     = LS_MESSAGE_FOR_ROUTING_IND;
    p->sig.signal    = LS_SIGNAL_LRI;
    p->lri.mh.ni     = ls->config.ni;
    p->lri.mh.mp     = 0x3;
    p->lri.mh.si     = 0x0;
    p->lri.mh.rl.dpc = ls->config.apc;
    p->lri.mh.rl.opc = ls->config.lpc;
    p->lri.mh.rl.sls = lk->config.slc;  /* FIXME */
    p->lri.slc       = lk->config.slc;
    lk_hmrt_tlac_remote_inhibit_test(lk, mp);
}

static inline void lk_tlac_send_uninhibit_ack(lk_t *lk, mblk_t *mp)
{
    ls_t *ls;
    ls_prim_t *p;
    if ( !(mp = __msg_alloc(mp)) ) return;
    ls = lk->module;
    p = (ls_prim_t *)mp->b_rptr;
    p->primitive     = LS_MESSAGE_FOR_ROUTING_IND;
    p->sig.signal    = LS_SIGNAL_LUA;
    p->lua.mh.ni     = ls->config.ni;
    p->lua.mh.mp     = 0x3;
    p->lua.mh.si     = 0x0;
    p->lua.mh.rl.dpc = ls->config.apc;
    p->lua.mh.rl.opc = ls->config.lpc;
    p->lua.mh.rl.sls = lk->config.slc;  /* FIXME */
    p->lua.slc       = lk->config.slc;
    lk_hmrt_tlac_uninhibit_ack(lk, mp);
}

static inline void lk_tlac_send_uninhibit_signalling_link(lk_t *lk, mblk_t *mp)
{
    ls_t *ls;
    ls_prim_t *p;
    if ( !(mp = __msg_alloc(mp)) ) return;
    ls = lk->module;
    p = (ls_prim_t *)mp->b_rptr;
    p->primitive     = LS_MESSAGE_FOR_ROUTING_IND;
    p->sig.signal    = LS_SIGNAL_LUN;
    p->lun.mh.ni     = ls->config.ni;
    p->lun.mh.mp     = 0x3;
    p->lun.mh.si     = 0x0;
    p->lun.mh.rl.dpc = ls->config.apc;
    p->lun.mh.rl.opc = ls->config.lpc;
    p->lun.mh.rl.sls = lk->config.slc;  /* FIXME */
    p->lfu.slc       = lk->config.slc;
    lk_hmrt_tlac_uninhibit_signalling_link(lk, mp);
}


/*
 *  Link states used by this state machine:
 *
 *  LK_STATE_UNAVAILABLE    (default)
 *  LK_STATE_SP_RESTARTING
 *  LK_STATE_AVAILABLE
 *
 */

/*
 *  Signalling Traffic Management (STM)
 *  Link Availability Control (TLAC)
 *  Figure 28/Q.704
 */

static inline void lk_t14_timeout(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
        case LK_STATE_UNAVAILABLE:
            lk->statem.local_inhibit_in_progress = 0;
            lk_tsrc_tlac_local_inhibit_request(lk);
            break;
    }
}

static inline void lk_t22_timeout(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            break;
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.locally_inhibited ) {
                lk_tlac_send_local_inhibit_test(lk, NULL);
                lk_timer_start(t22);
            }
            break;
    }
}

static inline void lk_t23_timeout(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            break;
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.remotely_inhibited ) {
                lk_tlac_send_remote_inhibit_test(lk, NULL);
                lk_timer_start(t23);
            }
            break;
    }
}

static inline void lk_tlac_tsrc_remote_inhibit_denied(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk_tlac_send_inhibit_denied(lk, NULL);
            break;
    }
}

static inline void lk_tlac_hmdt_inhibit_signalling_link(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk_tsrc_tlac_remote_inhibit_request(lk);
            break;
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.remotely_inhibited ) {
                lk_tlac_send_inhibit_ack(lk, mp);
            } else {
                lk->statem.remotely_inhibited = 0;
                lk_tlac_send_inhibit_ack(lk, mp);
                lk_tsrc_tlac_link_inhibited(lk);
                lk_timer_start(t22);
            }
            return;
    }
    freemsg(mp);
}

static inline void lk_tlac_mgmt_inhibit_signalling_link(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
        case LK_STATE_UNAVAILABLE:
            lk_tsrc_tlac_local_inhibit_request(lk);
            break;
    }
}

static inline void lk_tlac_tsrc_local_inhibit_allowed(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
        case LK_STATE_UNAVAILABLE:
            lk_tlac_send_inhibit_signalling_link(lk, NULL);
            lk->statem.local_inhibit_in_progress = 1;
            lk_timer_start(t14);
            break;
    }
}

static inline void lk_tlac_tsrc_local_inhibit_denied(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
        case LK_STATE_UNAVAILABLE:
            lk_mgmt_tlac_inhibit_denied(lk);
            break;
    }
}

static inline void lk_tlac_hmdt_inhibit_denied(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk_mgmt_tlac_inhibit_denied(lk);
            lk->statem.local_inhibit_in_progress = 0;
            lk_timer_stop(t14);
            break;
    }
}

static inline void __lk_tlac_changeover(lk_t *lk)
{
    if ( lk->statem.changeback_in_progress ) {
        lk->statem.unavailable = 1;
        lk_tsrc_tlac_signalling_link_unavailable(lk);
    } else {
        lk_tcoc_tlac_signalling_link_unavailable(lk);
        lk_tsrc_tlac_signalling_link_unavailable(lk);
        lk->statem.changeover_in_progress = 1;
    }
    lk->statem.tlac_state = LK_STATE_UNAVAILABLE;
}

static inline void lk_tlac_hmdt_inhibit_ack(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            if ( lk->statem.local_inhibit_in_progress ) {
                lk->statem.locally_inhibited = 1;
                lk->statem.local_inhibit_in_progress = 0;
                lk_timer_stop(t14);
                lk_tsrc_tlac_link_inhibited(lk);
                lk_mgmt_tlac_link_inhibited(lk);
                lk_timer_start(t22);
                __lk_tlac_changeover(lk);
            }
            break;
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.local_inhibit_in_progress ) {
                lk->statem.locally_inhibited = 1;
                lk_tsrc_tlac_link_inhibited(lk);
                lk_mgmt_tlac_link_inhibited(lk);
                lk_timer_stop(t14);
                lk_timer_start(t22);
            }
            break;
    }
}

static inline void lk_tlac_tsrc_remote_inhibit_allowed(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk->statem.remotely_inhibited = 1;
            lk_tlac_send_inhibit_ack(lk, NULL);
            lk_tsrc_tlac_link_inhibited(lk);
            lk_mgmt_tlac_link_inhibited(lk);
            lk_timer_start(t23);
            __lk_tlac_changeover(lk);
            break;
    }
}

static inline void lk_tlac_mgmt_local_processor_outage(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk->statem.local_blocked = 1;
            __lk_tlac_changeover(lk);
            break;
        case LK_STATE_UNAVAILABLE:
            lk->statem.local_blocked = 1;
            lk->statem.failed = 0;
            break;
    }
}

static inline void lk_tlac_lsac_signalling_link_failed(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk->statem.failed = 1;
            __lk_tlac_changeover(lk);
            break;
        case LK_STATE_UNAVAILABLE:
            lk->statem.failed = 1;
            lk->statem.local_blocked = 0;
            lk->statem.remote_blocked = 0;
            lk_timer_stop(t24); /* national option */
            break;
        case LK_STATE_SP_RESTARTING:
            lk->statem.failed = 1;
            lk->statem.unavailable = 1;
            lk_tsrc_tlac_signalling_link_unavailable(lk);
            lk_tcoc_tlac_signalling_link_unavailable(lk);
            lk_tprc_tlac_signalling_link_unavailable(lk);
            break;
    }
}

static inline void lk_tlac_lsac_remote_processor_outage(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk->statem.remote_blocked = 1;
            lk_lsac_tlac_local_processor_outage(lk); /* national option */
            __lk_tlac_changeover(lk);
            break;
        case LK_STATE_UNAVAILABLE:
            lk->statem.remote_blocked = 1;
            lk->statem.failed = 0;
            break;
        case LK_STATE_SP_RESTARTING:
            lk->statem.remote_blocked = 1;
            lk->statem.unavailable = 1;
            lk_tsrc_tlac_signalling_link_unavailable(lk);
            lk_tcoc_tlac_signalling_link_unavailable(lk);
            lk_tprc_tlac_signalling_link_unavailable(lk);
            break;
    }
}

static inline void lk_tlac_lsac_remote_processor_recovered(lk_t *lk) /* national option */
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
#if national_option
            lk->statem.remote_blocked = 0;
            if ( lk->timers.t24 ) { /* t24 is running */
                if ( lk->statem.changeover_in_progress )
                    lk_tcoc_tlac_signalling_link_available(lk);
                else {
                    lk_tcbc_tlac_signalling_link_available(lk);
                    lk->statem.changeback_in_progress = 1;
                    lk_lsac_tlac_signalling_link_available(lk);
                    lk->statem.tlac_state = LK_STATE_AVAILABLE;
                }
            }
#else
            lk->statem.remote_blocked = 0;
            if ( !lk->statem.local_blocked ) {
                if ( lk->statem.changeover_in_progress )
                    lk_lsac_tlac_continue(lk);
                else
                    lk_lsac_tlac_flush_buffers(lk);
            }
#endif

            break;
        case LK_STATE_SP_RESTARTING:
            lk->statem.remote_blocked = 0;
            lk->statem.unavailable = 0;
            lk_tsrc_tlac_signalling_link_available(lk);
            lk_tprc_tlac_signalling_link_unavailable(lk);
            break;
    }
}

static inline void lk_tlac_mgmt_local_processor_recovered(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            lk->statem.local_blocked = 0;
            if ( !lk->statem.remote_blocked ) {
#if national_option
#else
                if ( lk->statem.changeover_in_progress )
                    lk_lsac_tlac_continue(lk);
                else
                    lk_lsac_tlac_flush_buffers(lk);
#endif
                if ( !lk->statem.locally_inhibited && !lk->statem.remotely_inhibited ) {
                    if ( lk->statem.changeover_in_progress ) {
                        lk_tcoc_tlac_signalling_link_available(lk);
                    } else {
                        lk_tcbc_tlac_signalling_link_available(lk);
                        lk->statem.changeback_in_progress = 1;
#if national_option
                        lk_lsac_tlac_signalling_link_available(lk);
#else
                        lk_tsrc_tlac_signalling_link_available(lk);
#endif
                        lk->statem.tlac_state = LK_STATE_AVAILABLE;
                    }
                }
            }
            break;
    }
}

static inline void lk_tlac_hmdt_changeover_order(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    int fsnc = ((ls_prim_t *)mp->b_rptr)->coo.fsnc;
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk->statem.failed = 1;
            lk_lsac_tlac_changeover_order_received(lk);
            if ( lk->statem.changeback_in_progress ) {
                lk->statem.changeover_order = 1;
                lk_tsrc_tlac_signalling_link_unavailable(lk);
            } else {
                lk_tcoc_tlac_changeover_order(lk, fsnc);
                lk->statem.changeover_in_progress = 1;
            }
            lk->statem.tlac_state = LK_STATE_UNAVAILABLE;
            break;
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.changeover_in_progress )
                lk_tcoc_tlac_changeover_order(lk, fsnc);
            else {
                lk_tlac_send_emergency_changeover_ack(lk, mp);
                return;
            }
            break;
    }
    freemsg(mp);
}

static inline void lk_tlac_tcbc_changeback_terminated(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk->statem.changeback_in_progress = 0;
            lk->statem.tlac_state = LK_STATE_AVAILABLE;
            break;
        case LK_STATE_UNAVAILABLE:
            lk->statem.changeback_in_progress = 0;
            if ( lk->statem.changeover_order )
                lk_tcoc_tlac_changeover_order(lk, lk->statem.fsnc); /* FIXME: ??? */
            else {
                if ( lk->statem.emergency_changeover_order )
                    lk_tcoc_tlac_emergency_changeover_order(lk);
                else
                    if ( lk->statem.unavailable )
                        lk_tcoc_tlac_signalling_link_unavailable(lk);
            }
            lk->statem.unavailable = 0;
            lk->statem.emergency_changeover_order = 0;
            lk->statem.changeover_order = 0;
            lk->statem.changeover_in_progress = 1;
            lk->statem.tlac_state = LK_STATE_UNAVAILABLE;
            break;
    }
}

static inline void lk_tlac_hmdt_emergency_changeover_order(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk->statem.failed = 1;
            lk_lsac_tlac_changeover_order_received(lk);
            if ( lk->statem.changeback_in_progress ) {
                lk->statem.emergency_changeover_order = 1;
                lk_tsrc_tlac_signalling_link_unavailable(lk);
            } else {
                lk_tcoc_tlac_emergency_changeover_order(lk);
                lk->statem.changeover_in_progress = 1;
            }
            lk->statem.tlac_state = LK_STATE_UNAVAILABLE;
            break;
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.changeover_in_progress )
                lk_tcoc_tlac_emergency_changeover_order(lk);
            else {
                lk_tlac_send_emergency_changeover_ack(lk, mp);
                return;
            }
            break;
    }
    freemsg(mp);
}

static inline void lk_tlac_lsac_signalling_link_in_service(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            lk->statem.failed = 0;
            lk_timer_stop(t24); /* national option */
            if ( !lk->statem.locally_inhibited && !lk->statem.remotely_inhibited ) {
                if ( lk->statem.changeover_in_progress ) {
                    lk_tcoc_tlac_signalling_link_available(lk);
                } else {
                    lk_tcbc_tlac_signalling_link_available(lk);
                    lk->statem.changeback_in_progress = 1;
#if national_option
                    lk_lsac_tlac_signalling_link_available(lk);
#else
                    lk_tsrc_tlac_signalling_link_available(lk);
#endif
                    lk->statem.tlac_state = LK_STATE_AVAILABLE;
                }
            }
            break;
        case LK_STATE_SP_RESTARTING:
            lk->statem.failed = 0;
            lk->statem.unavailable = 0;
            lk_tsrc_tlac_signalling_link_available(lk);
            lk_tprc_tlac_signalling_link_unavailable(lk);
            break;
    }
}

static inline void lk_tlac_lsac_link_in_service_at_level_2(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
        case LK_STATE_SP_RESTARTING:
            lk_tsrc_tlac_link_in_service_at_level_2(lk);
            break;
    }
}

static inline void lk_tlac_tcoc_changeover_not_required(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            lk->statem.changeover_in_progress = 0;
#if national_option
            lk_lsac_tlac_signalling_link_available(lk);
#else
            lk_tsrc_tlac_signalling_link_available(lk);
#endif
            lk->statem.tlac_state = LK_STATE_AVAILABLE;
            break;
    }
}

#if national_option
static inline void lk_t24_timeout(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            if ( !lk->statem.locally_inhibited &&
                    !lk->statem.remotely_inhibited &&
                    !lk->statem.failed &&
                    !lk->statem.local_blocked &&
                    !lk->statem.remote_blocked )
            {
                if ( lk->statem.changeback_required ) {
                    lk_tcbc_tlac_signalling_link_available(lk);
                    lk->statem.changeback_in_progress = 1;
                    lk_lsac_tlac_signalling_link_available(lk);
                } else {
                    lk_lsac_tlac_signalling_link_availabled(lk);
                }
                lk->statem.tlac_state = LK_STATE_AVAILABLE;
            }
            break;
    }
}

#endif
static inline void lk_tlac_tcoc_changeover_executed(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            lk->statem.changeover_in_progress = 0;
#if national_option
            lk_lsac_tlac_local_processor_recovered(lk);
            lk_timer_start(t24);
            lk->statem.changeback_required = 1;
#else
            if ( !lk->statem.locally_inhibited &&
                 !lk->statem.remotely_inhibited &&
                 !(lk->statem.failed && lk->statem.local_blocked) &&
                 !(lk->statem.failed && lk->statem.remote_blocked) )
            {
                lk_tcbc_tlac_signalling_link_available(lk);
                lk->statem.changeback_in_progress = 1;
                lk_tsrc_tlac_signalling_link_available(lk);
                lk->statem.tlac_state = LK_STATE_AVAILABLE;
            }
#endif
            break;
    }
}

static inline void lk_t12_timeout(lk_t *lk) {
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            lk->statem.uninhibit_in_progress = 0;
            if ( lk->statem.second_time_t12_expires ) {
                lk_mgmt_tlac_uninhibit_not_possible(lk);
                break;
            } else {
                lk->statem.second_time_t12_expires = 1;
                if ( lk->statem.management_request ) {
                    lk_tsrc_tlac_uninhibit_request(lk);
                } else {
                    lk_tlac_send_uninhibit_signalling_link(lk, NULL);
                    lk->statem.uninhibit_in_progress = 1;
                    lk_timer_start(t12);
                }
            }
            break;
    }
}

static inline void lk_tlac_tsrc_uninhibiting_not_possible(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.failed || lk->statem.local_blocked || lk->statem.remote_blocked ) {
                lk_mgmt_tlac_uninhibiting_not_possible(lk);
                lk->statem.management_request = 0;
            } else {
                lk_tlac_send_uninhibit_signalling_link(lk, NULL);
                lk->statem.uninhibit_in_progress = 1;
                lk_timer_start(t12);
            }
            break;
    }
}

static inline void lk_tlac_tsrc_uninhibiting_possible(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            lk_tlac_send_uninhibit_signalling_link(lk, NULL);
            lk->statem.uninhibit_in_progress = 1;
            lk_timer_start(t12);
            break;
    }
}

static inline void lk_tlac_hmdt_force_uninhibit_signalling_link(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk_tlac_send_uninhibit_signalling_link(lk, mp);
            return;
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.locally_inhibited || lk->statem.remotely_inhibited ) {
                lk_tlac_send_uninhibit_signalling_link(lk, mp);
                lk->statem.uninhibit_in_progress = 1;
                lk_timer_start(t12);
            } else {
                lk_tlac_send_uninhibit_signalling_link(lk, mp);
            }
            return;
    }
    freemsg(mp);
}

static inline void lk_tlac_mgmt_uninhibit_signalling_link(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            lk->statem.management_request = 1;
            lk_tsrc_tlac_uninhibit_request(lk);
            break;
    }
}

static inline void lk_tlac_hmdt_uninhibit_signalling_link(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.locally_inhibited || lk->statem.remotely_inhibited ) {
                lk->statem.remotely_inhibited = 0;
                lk_tlac_send_uninhibit_ack(lk, mp);
                lk_timer_stop(t13);
                lk->statem.second_time_t13_expires = 0;
                if ( !lk->statem.locally_inhibited ) {
                    lk_tsrc_tlac_cancel_link_inhibited(lk);
                    if ( !lk->statem.failed && !lk->statem.local_blocked && !lk->statem.remote_blocked ) {
                        if ( lk->statem.changeover_in_progress ) {
                            lk_tcoc_tlac_signalling_link_available(lk);
                        } else {
                            lk_tcbc_tlac_signalling_link_available(lk);
                            lk->statem.changeback_in_progress = 1;
#if national_option
                            lk_lsac_tlac_signalling_link_available(lk);
#else
                            lk_tsrc_tlac_signalling_link_available(lk);
#endif
                            lk->statem.tlac_state = LK_STATE_AVAILABLE;
                        }
                    }
                }
            } else {
                lk_tlac_send_uninhibit_ack(lk, mp);
            }
            return;
    }
    freemsg(mp);
}

static inline void lk_t13_timeout(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.second_time_t13_expires ) {
            } else {
                lk->statem.second_time_t13_expires = 1;
                lk_tlac_send_force_uninhibit_signalling_link(lk, NULL);
                lk_timer_start(t13);
            }
            break;
    }
}

static inline void lk_tlac_tsrc_uninhibit_signalling_link(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk_tlac_send_uninhibit_ack(lk, NULL);
            break;
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.failed || lk->statem.local_blocked || lk->statem.remote_blocked ) {
                if ( lk->statem.locally_inhibited ) {
                    lk_tlac_send_uninhibit_signalling_link(lk, NULL);
                    lk_timer_start(t12);
                    if ( lk->statem.remotely_inhibited ) {
                        lk_tlac_send_force_uninhibit_signalling_link(lk, NULL);
                        lk_timer_start(t13);
                    }
                }
            }
            break;
    }
}

static inline void lk_tlac_hmdt_uninhibit_ack(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_UNAVAILABLE:
            if ( lk->statem.uninhibit_in_progress ) {
                lk->statem.locally_inhibited = 0;
                lk->statem.management_request = 0;
                lk_mgmt_tlac_link_uninhibited(lk);
                lk->statem.uninhibit_in_progress = 0;
                lk_timer_stop(t12);
                lk->statem.second_time_t12_expires = 0;
                if ( !lk->statem.remotely_inhibited ) {
                    lk_tsrc_tlac_cancel_link_inhibited(lk);
                    if ( !lk->statem.failed && !lk->statem.local_blocked && !lk->statem.remote_blocked ) {
                        if ( lk->statem.changeover_in_progress ) {
                            lk_tcoc_tlac_signalling_link_available(lk);
                        } else {
                            lk_tcbc_tlac_signalling_link_available(lk);
                            lk->statem.changeback_in_progress = 1;
#if national_option
                            lk_lsac_tlac_signalling_link_available(lk);
#else
                            lk_tsrc_tlac_signalling_link_available(lk);
#endif
                            lk->statem.tlac_state = LK_STATE_AVAILABLE;
                        }
                    }
                }
            }
            break;
    }
}

static inline void lk_tlac_hmdt_local_inhibit_test(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk_tlac_send_force_uninhibit_signalling_link(lk, mp);
            lk_timer_start(t13);
            break;
        case LK_STATE_UNAVAILABLE:
            if ( !lk->statem.remotely_inhibited ) {
                lk_tlac_send_force_uninhibit_signalling_link(lk, mp);
                lk_timer_start(t13);
            } else
                freemsg(mp);
            break;
        default:
            freemsg(mp);
    }
}

static inline void lk_tlac_hmdt_remote_inhibit_test(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
            lk_tlac_send_uninhibit_signalling_link(lk, mp);
            lk_timer_start(t12);
            return;
        case LK_STATE_UNAVAILABLE:
            if ( !lk->statem.locally_inhibited ) {
                lk_tlac_send_uninhibit_signalling_link(lk, mp);
                lk_timer_start(t12);
            } else
                freemsg(mp);
            return;
    }
    freemsg(mp);
}

static inline void __lk_tlac_cancel_all_marks(lk_t *lk)
{
    lk->statem.local_inhibit_in_progress = 0;
    lk->statem.uninhibit_in_progress = 0;
    lk->statem.changeover_in_progress = 0;
    lk->statem.changeover_order = 0;
    lk->statem.emergency_changeover_order = 0;
    lk->statem.changeback_in_progress = 0;
    lk->statem.changeback_required = 0;
    lk->statem.local_blocked = 0;
    lk->statem.remote_blocked = 0;
    lk->statem.locally_inhibited = 0;
    lk->statem.remotely_inhibited = 0;
    lk->statem.failed = 0;
    lk->statem.management_request = 0;
    lk->statem.second_time_t12_expires = 0;
    lk->statem.second_time_t13_expires = 0;
    lk->statem.unavailable = 0;
}

static inline void lk_tlac_tprc_restart_begins(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
        case LK_STATE_UNAVAILABLE:
            __lk_tlac_cancel_all_marks(lk);
            lk->statem.unavailable = 1;
            lk->statem.tlac_state = LK_STATE_SP_RESTARTING;
            break;
    }
}

/*
 *  (Should really move this function to llsc where
 *  this can iterate over the entire linkset.)
 */
static inline void lk_tlac_tsrc_adjacent_sp_restarting(lk_t *lk)
{
    /*
     *  Only for those links in the direct linkset
     *  to the adjacent, restarting SP
     */
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_AVAILABLE:
        case LK_STATE_UNAVAILABLE:
            __lk_tlac_cancel_all_marks(lk);
            lk->statem.unavailable = 1;
            lk->statem.tlac_state = LK_STATE_SP_RESTARTING;
            break;
    }
}

static inline void lk_tlac_tsrc_adjacent_sp_restarted(lk_t *lk)
{
    /*
     *  Only for those links in the direct linkset
     *  to the adjacent, restarting SP
     */
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_SP_RESTARTING:
            if ( lk->statem.unavailable )
                lk->statem.tlac_state = LK_STATE_UNAVAILABLE;
            else
                lk->statem.tlac_state = LK_STATE_AVAILABLE;
            break;
    }
}

static inline void lk_tlac_tprc_restart_ends(lk_t *lk)
{
    switch ( lk->statem.tlac_state ) {
        case LK_STATE_SP_RESTARTING:
            if ( lk->statem.unavailable )
                lk->statem.tlac_state = LK_STATE_UNAVAILABLE;
            else
                lk->statem.tlac_state = LK_STATE_AVAILABLE;
            break;
    }
}

/*
 *  10      Management Inhibiting
 *
 *  10.1    General
 *
 *  Signalling link management inhibiting is requested by management when it becomes
 *  necessary, e.g. for maintenance or testing purposes (for example, if the link
 *  experiences too many changeovers and changebacks in a short time, or there is a
 *  significant link error rate), to make or keep a signalling link unavailable to
 *  User Part-generated signalling traffic.  Management inhibiting is a signalling
 *  traffic management action, and does not cause any link status changes at level
 *  2.  A signalling link is marked "inhibited" under the management inhibiting
 *  procedure.  In particular, a signalling link that was active and in service
 *  prior to being inhibited will remain so, and will thus be able to transmit
 *  maintenance and test messages, for which the signalling link test message could
 *  be used (see clause 2/Q.707).
 *
 *  Inhibiting of a signalling link may be requested by management functions at
 *  either end of the link.  The request is granted, provided that the inhibiting
 *  action does not cause any previously accessible destination to become
 *  inaccessible at either end of the signalling link.  The request may also be
 *  refused under certain circumstances such as congestion.
 *
 *  A signalling link normally remains inhibited until uninhibiting is invoked in
 *  the signalling point at which inhibiting was initiated. Uninhibiting is
 *  initiated either at the request of a management function or by routing functions
 *  at either end of the signalling link when it is found that a destination has
 *  become inacessible for signalling traffic and the link sets associated with
 *  routes to that destination contains inhibited links.  Unless unavailable for
 *  other reasons, unihibiting causes the signalling link to enter the available
 *  state and changeback to be initiated.
 *
 *  Periodic tests are made on the inhibit status of inhibited links.  Such periodic
 *  tests should not add significantly to the traffic load on the signalling
 *  network, and remove the need for a signalling point to perform inhibit tests at
 *  signalling point restart.
 *
 *  If a test on the inhibit status of a link reveals discrepancies between the
 *  signalling points at each end of the link, the link is either uninhibited or
 *  force uninhibited as appropriate, to align the inhibit status at each end of the
 *  link.
 *
 *  10.2    Inhibiting initiation and actions
 *
 *  When at signalling point X a request is received from a management function to
 *  inhibit a signalling link to signalling point Y, the following action take
 *  place:
 *
 *  a)  A check if performed at signalling point X to determine whether, in the case
 *      of an available link, inhibiting will result in a destination becoming
 *      inaccessible, or in the case of an unavailable link, signalling point Y is
 *      inaccesible.  If either is the case, management is informed that the
 *      inhibiting request is denied.
 *
 *  b)  If inhibiting is permitted, signalling point X sends an inhibit message to
 *      signalling point Y indicating that it wishes to inhibit the signalling link
 *      identified in the message.
 *
 *  c)  Signalling point Y, on receiving the inhibit message from X, checks whether,
 *      in the case of an available link, inhibiting will result in a destination
 *      becoming inaccessible and, if so, an inhibit denied message is returned to
 *      signalling point X.  The latter then informs the management function which
 *      requested inhibiting that the request cannot be granted.
 *
 *  d)  If the signalling point Y finds that inhibiting of the concerned link is
 *      permissible, it sends an inhibit acknowledgement to signalling point X and
 *      marks the link remotely inhibited.
 *
 *      If the link concerned is currently carrying traffic, signalling point Y
 *      sends the inhibit acknowledgement via that link and diverts subsequent
 *      traffic for it, using the time controlled changeover procedure.  Y then
 *      starts inhibit test timer T23.
 *
 *  e)  On receiving an inhibit acknowledgement message, signalling point X marks
 *      the link locally inhibited and informs management that the link is
 *      inhibited.
 *
 *      If the link concerned is currently carrying traffic, signalling point X
 *      diverts subsequent traffic for that link, using the time-controlled
 *      changeover procedure.  X then starts inhibit test timer T22.
 *
 *  f)  When changeover has been completed, the link while inhibited, will be
 *      unavailable for the transfer of user-generated traffic but still permits the
 *      exchange of test messages.
 *
 *  g)  If, for any reason, the inhibit acknowledgement message is not received, a
 *      timer T14 expires and the procedure is restarted including inspection of the
 *      status of the destination of the inhibit message.  If the destination is not
 *      available, management is informed.
 *
 *  At most two consecutive automatic attempts may be made to inhibit a particular
 *  signalling link.
 *
 *  A signalling point may not transmit an inhibit message for a particular
 *  signalling link if it has already transmitted an uninhibit message for that
 *  link, and neither an acknowledgement for that uninhibit message has been
 *  received nor has the uninhibit procedure finally timed out.
 *
 *  10.3    Uninhibited initiation and actions
 *
 *  Signalling link uninhibiting is initiated at the signalling point which
 *  originally caused the link to be inhibited, upon receipt of an uninhibit or
 *  forced uninhibit request.
 *
 *  In a given signalling point, an uninhibit request may be initiated for a locally
 *  inhibited link by the management or signalling route control function, while a
 *  forced uninhibit request may be initiated for a remotely inhibited link by the
 *  signalling routing control function only.
 *
 *  Signalling routing control will initiate signalling link uninhibit if an
 *  inhibited link is found to be a member of a link set in a route to a destination
 *  which has become inaccessible.
 *
 *  If such signalling routing control uninhibiting were unsuccessful because of a
 *  failed or block inhibited link, and if that link later recovers or becomes
 *  unblocked with the destination still unavailable, uninhibiting is re-attempted.
 *
 *  A signalling point may not transmit an uninhibit message for a particular
 *  signalling link if it has already transmitted an inhibit message for that link,
 *  and neither an acknowledgement for that inhibit message has been received nor
 *  has the inhibit procedure finally timed out.
 *
 *  10.3.1  Management-initiated uninhibiting
 *
 *  Upon receipt of an uninhibiting request from the management function of
 *  signalling point X regarding an inhibited link to signalling point Y, the
 *  following actions take place:
 *
 *  a)  A check is performed at signlaling point X to determine whether an uninhibit
 *      message can be sent to signalling point Y, either over an available route,
 *      or if all routes to signalling point Y are unavailable, over the concerned
 *      inhibited link.  If all routes to signalling point Y are unavailable and the
 *      concerned inhibited link is marked failed or processor outage, management is
 *      informed that uninhibiting is not possible.
 *
 *  b)  If uninhibiting is possible, signalling point X sends uninhibit signalling
 *      link message to signalling point Y indicating that the link identified in
 *      the message should be uninhibited.
 *
 *  c)  Upon receipt of the uninhibit link message, signalling point Y returns an
 *      uninhibit acknowledgement message to signalling point X and cancels the
 *      remote inhibit indication.  If no local inhibited, failed or blocked
 *      condition exists on the link, it is put in the available state and
 *      changeback is initiated.
 *
 *  d)  On receipt of the uninhibit acknowledgement message, signalling point X
 *      cancels the local inhibit indication and informs management that the link
 *      has be uninhibited.  If no remote inhibited, failed or blocked condition
 *      exists on the link, it is put in the available state and changeback is
 *      initiated.
 *
 *  e)  If, for any reason, the uninhibit acknowledgement message is not received, a
 *      timer T12 expires.  If this is the first expirty of T12 for this
 *      uninhibition attempt on this link, the procedure is restarted including
 *      inspection of the status of the destination of the uninhibit message.  If
 *      the destination is not available, or T12 has expired for the second time
 *      during the uninhibition attempt on this link, management is informed, and
 *      the uninhibition is abandoned.
 *
 *  10.3.2  Signalling routing control initiated uninhibiting
 *
 *  Upon receipt of an uninhibit request for signalling routing control at
 *  signalling point X regarding an inhibited link to signalling point Y, the
 *  following actions take place:
 *
 *  a)  A check is performed at signalling point X to determine whether the
 *      concerned inhibited link is marked failed or blocked.  If it is, then
 *      signalling point X is unable to transmit an uninhibit message to signalling
 *      point Y, uninhibiting is therefore not possible, and the uninhibiting
 *      attempt is abandoned.
 *
 *  b)  If unihibiting is possible, a further check is performed by signalling point
 *      X to determine whether inhibiting initiated by X (local inhibiting) or
 *      inhibiting initiated by Y (remote inhibiting) is in effect.
 *
 *  c)  If local inhibiting is in effect, then the actions described 10.3.1 b), c),
 *      d) and e) take place.  If uninhibition is abandoned, step f) below is taken.
 *
 *  d)  If remote inhibiting is in effect, the signalling point X requests forced
 *      uninhibiting of the signalling link by sending a force uninhibit signalling
 *      link message to signalling point Y, which will then initiate uninhibiting in
 *      accordance with the description given in 10.3.1 b), c), d) and e).
 *
 *      The force uninhibit signalling link message is transmitted down the link to
 *      be uninhibited.
 *
 *  e)  If, for any reason, an unihibit signalling link message is not received in
 *      response to the force uninhibit message, a timer T13 expires.  If this is
 *      the first expiry of T13 for this uninhibition attempt on this link, the
 *      procedure is restarted including inspection of the status of the inhibited
 *      link.  If the link is marked failed or blocked, or timer T13 has expired for
 *      the second time during inhibition of this link, management is informed and
 *      the uninhibition is abandoned.
 *
 *  f)  If an attempt to uninhibit a signalling link is abandoned, signalling
 *      routing control attempts to uninhibit the next inhibited link to signaling
 *      point Y, starting from a) above.  The search continues until either a link
 *      is successfully uninhibited or all possible links to Y in the routing table
 *      have been exhausted, or the destination has become available for other
 *      reasons.
 *
 *  10.4    Receipt of unexpected management inhibition messages
 *
 *  a)  An inhibit signalling link message concerning an inhibited signalling link
 *      is answered with an inhibit acknowledgement message without taking any
 *      further action.
 *
 *  b)  An uninhibit signalling link message concerning an uninhibited signalling
 *      link is answered with an uninhibit acknowledgement message without taking
 *      any further action.
 *
 *  c)  A force unihibit signalling link message concerning an unihibited link is
 *      answered with an uninhibit signalling link message without taking any
 *      further action.
 *
 *  d)  If an inhibit acknowledgement message is received and no inhibit signalling
 *      link message is outstanding for the concerned link, no action is taken.
 *
 *  e)  If an uninhibit acknowledgement message is received and no unihibit
 *      signalling link message is outstanding for the concerned link, no action is
 *      taken.
 *
 *  10.5    Management inhibited link and processor recovery
 *
 *  a)  After a local processor recovery that involves the loss of inhibit status
 *      information, the signalling point will mark all links as unihibited, and
 *      message traffic will be restarted.
 *
 *  b)  If messages for Level 4 are received on an inhibited signalling link, the
 *      messages will be discriminated and distributed.
 *
 *  10.6    Inhibit test procedure
 *
 *  When a signalling link becomes management inhibited, periodic tests are started
 *  to guard the inhibition status at each end of the link.
 *
 *  10.6.1  A local inhibit test is performed when timer T22 expires at signalling
 *  point X and the concerned link is marked locally inhibited.  In this case, a
 *  local inhibit test message is sent to the signalling point Y at the other end of
 *  the link, and timer T22 is restarted.
 *
 *  Reception of a local inhibit test message causes:
 *
 *  i)  no action, if the concerned link is marked remotely inhibited at the
 *      receiving signalling point Y; or
 *
 *  ii) the force uninhibit procedure to be involved at the receiving signalling
 *      point Y, if the concerned signalling link is not marked remotely inhibited
 *      at Y.  This procedure causes the locally inhibited status of the link at X
 *      to be cancelled.
 *
 *  If a timer T22 expires at the concerned link is not locally inhibited, no
 *  further action is taken.
 *
 *  10.6.2  A remote inihibit test is performed when timer T23 expires at signalling
 *  point Y and the concerned link is marked remotely inhibited.  In this case a
 *  remote inhibit test message is sent to signalling point X at the other end of
 *  the link; and timer T23 is restarted.
 *
 *  Reception of a remote inhibit test message causes:
 *
 *  i)  no action, if teh concerned link is marked locally inhibited at the
 *      receiving signalling point X; or
 *
 *  ii) the uninhibit procedure to be invoked at the receiving signalling point X,
 *      if the concerned link is not marked locally inhibited at X.  This procedure
 *      causes the remotely inihibited status of the link at Y to be cancelled.
 *
 *  If a timer T23 expires and the concerned link is not remotely inhibited, no
 *  further action is taken.
 */

#endif  __SLS_TLAC_H__

