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

 @(#) $Id: sls_tsrc.h,v 0.7.2.3 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_TSRC_H__
#define __SLS_TSRC_H__

/*
 *  Consistent with link set and link functions of:
 *
 *      Signalling Traffic Management (STM)
 *      Signalling Routing Control (TSRC)
 *      Figure 29/Q.704
 *
 *  Note:- the TSRC state machine is a complicated state machine which
 *  includes functions at the route set, route, link set, and link level.
 *  This is the link set and link functions only (the state machine has been
 *  partitioned between MTP and SLS).
 */

/*
 *  Referenced functions.
 */

/*
 *  Forward declarations.
 */

/*
 *  Message building functions.
 */

/*
 *  Timeout functions.
 */

/*
 *  Primitive functions.
 */

static inline void lk_tsrc_tlac_signalling_link_unavailable(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( lk->statem.tsrc_state ) {
        case LK_STATE_IDLE:
            lk->statem.link_unavailable = 1;
            ls->statem.links_available--;
            if ( /* emergency see 12.2.4 */ )
                lk_llsc_tsrc_emergency(lk);
            if ( !ls->statem.links_available )
                lk_tsrc_tsrc_signalling_link_set_unavailable(lk);
            break;
    }
}

static inline void lk_tsrc_tlac_signalling_link_available(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( lk->statem.tsrc_state ) {
        case LK_STATE_IDLE:
            lk->statem.link_available = 1;
            ls->statem.links_available++;
            if ( /* not emergency see 12.2.4 */ )
                lk_llsc_tsrc_emergency_ceases(lk);
            if ( ls->statem.links_available == 1 )
                lk_tsrc_tsrc_signalling_link_set_available(lk);
            break;
    }
}

static inline void lk_tsrc_tlac_link_in_service_at_level_2(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( lk->statem.tsrc_state ) {
        case LK_STATE_IDLE:
            lk->statem.link_in_service_at_level_2 = 1;
            ls->statem.links_in_service_at_level_2++;
            if ( ls->statem.links_in_service_at_level_2 > 1 ) {
                if ( ls->statem.adjacent_sp_inacessible ) {
                    lk_tsrc_tsrc_adjacent_sp_restarting(lk);
                }
            } else {
                lk_tsrc_tprc_signalling_point_restart_indication(lk);
                ls->statem.own_sp_restarting = 1;
            }
            break;
    }
}

static inline void lk_tsrc_tcoc_alternative_routing_data_request(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( lk->statem.tsrc_state ) {
        case LK_STATE_IDLE:
            /* obtain alternative routing data according to rules specified in Q.704 4.4 */
            /* during SP restart the adjacent SP is considered inaccessible */
            /* locally or request from MTP level state machine */
            lk_tcoc_tsrc_alternative_routing_data(lk);
            lk->statem.tsrc_state = LK_STATE_WAIT01;
            break;
    }
}

static inline void lk_tsrc_tcbc_alternative_routing_data_request(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( lk->statem.tsrc_state ) {
        case LK_STATE_IDLE:
            /* obtain alternative routing data */
            /* during SP restart the adjacent SP is considered inaccessible */
            /* locally or request from MTP level state machine */
            lk_tcbc_tsrc_alternative_routing_data(lk);
            lk->statem.tsrc_state = LK_STATE_WAIT02;
            break;
    }
}

static inline void lk_tsrc_lsda_alternative_routing_data_request(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( lk->statem.tsrc_state ) {
        case LK_STATE_WAIT01:
            /* obtain alternative routing data */
            /* locally or request from MTP level state machine */
            lk_tcbc_lsda_alternative_routing_data(lk);
            break;
    }
}

static inline void lk_tsrc_tcoc_changeover_not_required(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( lk->statem.tsrc_state ) {
        case LK_STATE_WAIT01:
            lk->statem.tsrc_state = LK_STATE_IDLE;
            break;
    }
}

static inline void lk_tsrc_tcoc_changeover_executed(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( lk->statem.tsrc_state ) {
        case LK_STATE_WAIT01:
            lk->statem.changeover_completed = 1;
            lk->statem.tsrc_state = LK_STATE_IDLE;
            break;
    }
}

static inline void lk_tsrc_tcbc_procedure_terminated(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( lk->statem.tsrc_state ) {
        case LK_STATE_WAIT02:
            lk->statem.changeover_completed = 0;
            lk->statem.tsrc_state = LK_STATE_IDLE;
            break;
    }
}

static inline void lk_tsrc_tprc_restart_begins(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( lk->statem.tsrc_state ) {
        case LK_STATE_WAIT01:
        case LK_STATE_WAIT02:
            lk->statem.tsrc_state = LK_STATE_IDLE;
            break;
    }
}

static inline void lk_tsrc_l2_congestion_status(lk_t *lk, int cong, int disc)
{
    ls_t *ls = lk->module;
    switch ( lk->statem.tsrc_state ) {
        case LK_STATE_IDLE:
            lk->statem.cong_status = cong;
            lk->statem.disc_status = disc;
            if ( ls->statem.cong_status < cong ) ls->statem.cong_status = cong;
            if ( ls->statem.disc_status < cong ) ls->statem.disc_status = disc;
            /* FIXME: need to drop back congestion status
             * for link set as well. */
            if ( /* link set congestion status has changed */ )
                lk_tsrc_tsrc_congestion_status(lk, ls->statem.cong_status, ls->statem.disc_status);
            break;
    }
}

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_link_inhibited(lk_t *lk);
static inline void lk_tsrc_tlac_cancel_link_inhibited(lk_t *lk);
static inline void lk_tsrc_tlac_uninhibit_request(lk_t *lk);
static inline void lk_tsrc_l2_signalling_link_congested(lk_t *lk);
static inline void lk_tsrc_l2_signalling_link_uncongested(lk_t *lk);

#endif  __SLS_TSRC_H__

