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

 @(#) $Id: sls_llsc.h,v 0.7.2.4 2001/02/03 05:48:54 brian Test $

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

 Copyright (C) 1997, 1998, 1999, 2000  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_LLSC_H__
#define __SLS_LLSC_H__

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

/* link and linkset functions */

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

/*
 *  Forward declarations.
 */

static inline void ls_llsc_mgmt_activate_link_set(ls_t *ls);    /* from MGMT */
static inline void ls_llsc_mgmt_deactivate_link_set(ls_t *ls);  /* from MGMT */

static inline void ls_llsc_tprc_restart_begins(ls_t *ls);       /* from MTP */
static inline void ls_llsc_tprc_restart_ends(ls_t *ls);         /* from MTP */

static inline void ls_llsc_tsrc_emergency(ls_t *ls);            /* from MTP */
static inline void ls_llsc_tsrc_emergency_ceases(ls_t *ls);     /* from MTP */

static inline void ls_llsc_lsac_activate_another_link(ls_t *ls);
static inline void ls_llsc_lsac_link_active(lk_t *lk);
static inline void ls_llsc_lsac_link_failed(lk_t *lk);
static inline void ls_llsc_lsac_link_inactive(lk_t *lk);

/*
 *  Signalling Link Managment (SLM)
 *  Link Set Control (LLSC)
 *  Figure 36/Q.704
 */

static inline void ls_llsc_mgmt_activate_link_set(ls_t *ls)
{
    lk_t *lk;
    switch ( ls->statem.llsc_state ) {
        case LS_STATE_INACTIVE:
            ls->statem.llsc_state = LS_STATE_ACTIVE;
        case LS_STATE_ACTIVE: /* Link set restart */
            ls->statem.links_active = 0;
            for ( lk = ls->device; lk; lk = lk->next ) {
                /* FIXME: Select links to activate */
                if ( lk->statem.lsac_state == LK_STATE_INACTIVE )
                    lk_lsac_llsc_activate_link(lk);
                else
                    ls->statem.links_active++;
            }
            break;
    }
}

static inline void ls_llsc_mgmt_deactivate_link_set(ls_t *ls)
{
    lk_t *lk;
    switch ( ls->statem.llsc_state ) {
        case LS_STATE_ACTIVE:
            for ( lk = ls->device; lk; lk = lk->next ) {
                if ( lk->statem.lsac_state == LK_STATE_INACTIVE ) /* why not send to all? */
                    lk_lsac_llsc_deactivate_link(lk);
            }
            lk->statem.llsc_state = LS_STATE_INACTIVE;
            break;
    }
}

static inline void ls_llsc_lsac_link_active(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( ls->statem.llsc_state ) {
        case LS_STATE_ACTIVE:
            if ( ++(ls->statem.links_active) > ls->config.links_specified ) {
                /* FIXME: Select a link to deactivate */
                for ( lk = ls->device; lk; lk = lk->next ) {
                    if ( lk->statem.lsac_state == LK_STATE_ACTIVE ) {
                        lk_lsac_llsc_deactivate_link(lk);
                        break;
                    }
                }
            }
            break;
    }
}

static inline void ls_llsc_lsac_link_failed(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( ls->statem.llsc_state ) {
        case LS_STATE_ACTIVE:
            if ( !(--ls->statem.links_active) ) {
                /* FIXME: Select links to activate */
                ls_llsc_mgmt_activate_link_set(ls);
            }
            break;
    }
}

static inline void ls_llsc_lsac_activate_another_link(ls_t *ls)
{
    lk_t *lk;
    switch ( ls->statem.llsc_state ) {
        case LS_STATE_ACTIVE:
            if ( ls->statem.links_active < ls->config.links_specified ) {
                /* FIXME: Select a link to activate */
                for ( lk = ls->device; lk; lk = lk->next ) {
                    if ( lk->statem.lsac_state == LK_STATE_INACTIVE ) {
                        lk_lsac_llsc_activate_link(lk);
                        break;
                    }
                }
            }
            break;
    }
}

static inline void ls_llsc_tsrc_emergency(ls_t *ls)
{
    lk_t *lk;
    switch ( ls->statem.llsc_state ) {
        case LS_STATE_ACTIVE:
            for ( lk = ls->device; lk; lk = lk->next )
                lk_lsac_llsc_emergency(lk);
            break;
    }
}

static inline void ls_llsc_tsrc_emergency_ceases(ls_t *ls)
{
    lk_t *lk;
    switch ( ls->statem.llsc_state ) {
        case LS_STATE_ACTIVE:
            for ( lk = ls->device; lk; lk = lk->next )
                lk_lsac_llsc_emergency_ceases(lk);
            break;
    }
}

static inline void ls_llsc_lsac_link_inactive(lk_t *lk)
{
    ls_t *ls = lk->module;
    switch ( ls->statem.llsc_state ) {
        case LS_STATE_ACTIVE:
            ls->statem.links_active--;
            break;
    }
}

static inline void ls_llsc_tprc_restart_begins(ls_t *ls)
{
    lk_t *lk;
    switch ( ls->statem.llsc_state ) {
        case LS_STATE_INACTIVE:
            ls->statem.llsc_state = LS_STATE_ACTIVE;
        case LS_STATE_ACTIVE:
            for ( lk = ls->device; lk; lk = lk->next )
                /* FIXME: Select links to activate */
                if ( lk->statem.lsac_state == LK_STATE_INACTIVE )
                    lk_lsac_llsc_activate_link(lk);
            break;
    }
}

static inline void ls_llsc_tprc_restart_ends(ls_t *ls)
{
    lk_t *lk;
    switch ( ls->statem.llsc_state ) {
        case LS_STATE_ACTIVE:
            for ( lk = ls->device; lk; lk = lk->next )
                lk_lsac_llsc_restart_ends(lk);
            break;
    }
}

#endif  __SLS_LLSC_H__

