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

 @(#) $Id: sls_lsac.h,v 0.7.2.5 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_LSAC_H__
#define __SLS_LSAC_H__

/*
 *  Referenced functions.
 *
 *  This state machine does not access any route or routeset functions.
 */

/* link and linkset functions */

static inline void lk_lsla_lsac_deactivate_link(lk_t *lk);
static inline void lk_lsla_lsac_restart_activation(lk_t *lk);
static inline void lk_lsla_lsac_start_activation(lk_t *lk);
static inline void lk_lsld_lsac_deactivate_link(lk_t *lk);

static inline void lk_lslr_lsac_restart_restoration(lk_t *lk);
static inline void lk_lslr_lsac_start_restoration(lk_t *lk);

static inline void lk_lsta_lsac_terminal_available(lk_t *lk);

static inline void lk_sltc_lsac_start_slt(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_link_in_service(lk_t *lk);

static inline void lk_llsc_lsac_activate_another_link(lk_t *lk);
static inline void lk_llsc_lsac_link_active(lk_t *lk);
static inline void lk_llsc_lsac_link_failed(lk_t *lk);
static inline void lk_llsc_lsac_link_inactive(lk_t *lk);

/*
 *  Forward declarations.
 */

static inline void lk_t17_timeout(lk_t *lk);

static inline void lk_lsac_mgmt_activate_link(lk_t *lk);            /* from MGMT */
static inline void lk_lsac_mgmt_deactivate_link(lk_t *lk);          /* from MGMT */

static inline void lk_lsac_l2_in_service(lk_t *lk);                 /* from L2 */
static inline void lk_lsac_l2_out_of_service(lk_t *lk);             /* from L2 */
static inline void lk_lsac_l2_remote_processor_outage(lk_t *lk);    /* from L2 */
static inline void lk_lsac_l2_remote_processor_recovered(lk_t *lk); /* from L2 */

static inline void lk_lsac_llsc_activate_link(lk_t *lk);
static inline void lk_lsac_llsc_deactivate_link(lk_t *lk);
static inline void lk_lsac_llsc_emergency(lk_t *lk);
static inline void lk_lsac_llsc_emergency_ceases(lk_t *lk);
static inline void lk_lsac_llsc_restart_ends(lk_t *lk);

static inline void lk_lsac_lsda_data_link(lk_t *lk);

static inline void lk_lsac_lsla_activation_unsuccessful(lk_t *lk);
static inline void lk_lsac_lsla_start_signalling_link(lk_t *lk);

static inline void lk_lsac_lsld_activation_not_possible(lk_t *lk);

static inline void lk_lsac_lslr_restoration_unsuccessful(lk_t *lk);
static inline void lk_lsac_lslr_start_signalling_link(lk_t *lk);

static inline void lk_lsac_lsta_deactivate_link(lk_t *lk);

static inline void lk_lsac_sltc_slt_failed(lk_t *lk);
static inline void lk_lsac_sltc_slt_successful(lk_t *lk);

static inline void lk_lsac_tcoc_stm_ready(lk_t *lk);
static inline void lk_lsac_tcoc_stop_l2(lk_t *lk);

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);

/*
 *  Signalling Link Management (SLM)
 *  Signalling Link Activity Control (LSAC)
 *  Figure 27/Q.704
 */

static inline void lk_lsac_lsda_data_link(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_INACTIVE:
            lk->statem.lsac_state = LK_STATE_ACTIVATING_RESTORING;
            lk_lsla_lsac_start_activation(lk);
            lk->statem.activation = 1;
            break;
    }
}

static inline void lk_lsac_llsc_activate_link(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_INACTIVE:
            lk->statem.lsac_state = LK_STATE_ACTIVATING_RESTORING;
            lk_lsla_lsac_start_activation(lk);
            lk->statem.activation = 1;
            break;
    }
}

static inline void lk_lsac_mgmt_activate_link(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_INACTIVE:
            lk->statem.lsac_state = LK_STATE_ACTIVATING_RESTORING;
            lk_lsla_lsac_start_activation(lk);
            lk->statem.activation = 1;
            break;
    }
}

static inline void lk_lsac_lsld_activation_not_possible(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            lk->statem.lsac_state = LK_STATE_INACTIVE;
            lk_lsld_lsac_deactivate_link(lk);
            if ( !lk->statem.activation_restoration_unsuccessful )
                lk_llsc_lsac_activate_another_link(lk);
            break;
    }
}

static inline void lk_lsac_llsc_emergency(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_INACTIVE:
            lk->statem.emergency = 1;
            break;
        case LK_STATE_ACTIVATING_RESTORING:
            lk->statem.emergency = 1;
            lk->dcalls->sl_emerg(lk);
            break;
        case LK_STATE_ACTIVE:
            lk->statem.emergency = 1;
            break;
    }
}

static inline void lk_lsac_llsc_emergency_ceases(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_INACTIVE:
            lk->statem.emergency = 0;
            break;
        case LK_STATE_ACTIVATING_RESTORING:
            lk->statem.emergency = 0;
            lk->dcalls->sl_normal(lk);
            break;
        case LK_STATE_ACTIVE:
            lk->statem.emergency = 0;
            break;
    }
}

static inline void lk_lsac_tlac_local_processor_outage(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_INACTIVE:
            lk->statem.local_processor_outage = 1;
            lk->dcalls->sl_lpo(lk); /* national option */
            break;
    }
}

static inline void lk_lsac_tlac_local_processor_recovered(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_INACTIVE:
            lk->statem.local_processor_outage = 0;
            lk->dcalls->sl_resume(lk); /* national option */
            break;
    }
}

static inline void lk_lsac_sltc_slt_successful(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            lk->statem.lsac_state = LK_STATE_ACTIVE;
            lk_tlac_lsac_link_in_service(lk);
            lk_llsc_lsac_link_active(lk);
            lk->statem.first_failure = 0;
            lk->statem.activation_restoration_unsuccessful = 0;
            break;
    }
}

static inline void lk_lsac_l2_in_service(lk_t *lk) /* from sl */
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            lk_sltc_lsac_start_slt(lk);
            break;
    }
}

static inline void lk_lsac_l2_out_of_service(lk_t *lk) /* from sl */
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            if ( lk->statem.first_failure ) {
                lk_lsta_lsac_terminal_available(lk);
                lk->statem.first_failure = 0;
            } else {
                lk->statem.first_failure = 1;
            }
            if ( lk->statem.activation ) {
                lk->statem.activation = 0;
                lk_lsla_lsac_restart_activation(lk);
            } else
                lk_lslr_lsac_restart_restoration(lk);
            break;
        case LK_STATE_ACTIVE:
            lk->statem.lsac_state = LK_STATE_FAILED;
            lk_tlac_lsac_signalling_link_failed(lk);
            lk_llsc_lsac_link_failed(lk);
            break;
    }
}

static inline void lk_t17_timeout(lk_t *lk)
{
    if ( lk->statem.lsac_state == LK_STATE_WAIT ) {
        lk->statem.lsac_state = LK_STATE_ACTIVATING_RESTORING;
        if ( lk->statem.emergency )
            lk->dcalls->sl_emerg(lk);
        lk->dcalls->sl_start(lk);
    }
}

static inline void lk_lsac_lsla_start_signalling_link(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            lk->statem.lsac_state = LK_STATE_WAIT;
            lk_timer_start(t17);
            break;
    }
}

static inline void lk_lsac_lslr_start_signalling_link(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            lk->statem.lsac_state = LK_STATE_WAIT;
            lk_timer_start(t17);
            break;
    }
}

static inline void lk_lsac_lsla_activation_unsuccessful(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            if ( !lk->statem.activation_restoration_unsuccessful ) {
                lk->statem.activation_restoration_unsuccessful = 1;
                lk_llsc_lsac_activate_another_link(lk);
            }
            break;
    }
}

static inline void lk_lsac_lslr_restoration_unsuccessful(lk_t *lk)
{
    lk_lsac_lsla_activation_unsuccessful(lk);
}

static inline void lk_lsac_llsc_deactivate_link(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            lk->statem.lsac_state = LK_STATE_INACTIVE;
            lk->dcalls->sl_stop(lk);
            lk_lsld_lsac_deactivate_link(lk);
            lk_lsla_lsac_deactivate_link(lk);
            lk_llsc_lsac_link_inactive(lk);
            if ( lk->statem.activation_restoration_unsuccessful )
                lk->statem.activation_restoration_unsuccessful = 0;
            else
                lk_llsc_lsac_activate_another_link(lk);
            break;
        case LK_STATE_ACTIVE:
            lk->statem.lsac_state = LK_STATE_WAIT;
            lk_tlac_lsac_signalling_link_failed(lk);
            break;
    }
}

static inline void lk_lsac_lsta_deactivate_link(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            lk_lsac_llsc_deactivate_link(lk);
            break;
        case LK_STATE_ACTIVE:
            lk->statem.lsac_state = LK_STATE_WAIT;
            lk_llsc_lsac_activate_another_link(lk);
            lk_lsac_llsc_deactivate_link(lk);
            break;
    }
}

static inline void lk_lsac_mgmt_deactivate_link(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            lk_lsac_llsc_deactivate_link(lk);
            break;
        case LK_STATE_ACTIVE:
            lk->statem.lsac_state = LK_STATE_WAIT;
            lk_llsc_lsac_activate_another_link(lk);
            lk_lsac_llsc_deactivate_link(lk);
            break;
    }
}

static inline void lk_lsac_sltc_slt_failed(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            lk_lsac_llsc_deactivate_link(lk);
            break;
    }
}

static inline void lk_lsac_llsc_restart_ends(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            lk_tlac_lsac_signalling_link_failed(lk);
            break;
    }
}

static inline void lk_lsac_l2_remote_processor_recovered(lk_t *lk) /* from sl */
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVATING_RESTORING:
            lk_sltc_lsac_start_slt(lk);
            break;
        case LK_STATE_ACTIVE:
            lk_tlac_lsac_remote_processor_recovered(lk);
            break;
    }
}

static inline void lk_lsac_tcoc_stop_l2(lk_t *lk)
{
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_ACTIVE:
            lk->statem.lsac_state = LK_STATE_FAILED;
            lk->dcalls->sl_stop(lk);
            lk_llsc_lsac_link_failed(lk);
            break;
    }
}

static inline void lk_lsac_tcoc_stm_ready(lk_t *lk)
{
    /*
     *  FAILED state and this primitive only required if retrieval cannot be
     *  carried out in parallel with signalling link restoration.
     */
    switch ( lk->statem.lsac_state ) {
        case LK_STATE_FAILED:
            lk->statem.lsac_state = LK_STATE_ACTIVATING_RESTORING;
            lk_lslr_lsac_start_restoration(lk);
            break;
        case LK_STATE_WAIT:
            lk->statem.lsac_state = LK_STATE_INACTIVE;
            lk->dcalls->sl_stop(lk);
            lk_lsld_lsac_deactivate_link(lk);
            lk_llsc_lsac_link_inactive(lk);
            break;
    }
}

static inline void lk_lsac_tlac_changeover_order_received(lk_t *lk)
{
    lk_lsac_tcoc_stop_l2(lk);
}

static inline void lk_lsac_tlac_flush_buffers(lk_t *lk)
{
    if ( lk->statem.lsac_state == LK_STATE_ACTIVE )
        lk->dcalls->sl_clear_bufs(lk);
}

static inline void lk_lsac_tlac_continue(lk_t *lk)
{
    if ( lk->statem.lsac_state == LK_STATE_ACTIVE )
        lk->dcalls->sl_resume(lk);
}

static inline void lk_lsac_l2_remote_processor_outage(lk_t *lk) /* from sl */
{
    if ( lk->statem.lsac_state == LK_STATE_ACTIVE )
        lk_tlac_lsac_remote_processor_outage(lk);
}

#endif  __SLS_LSAC_H__

