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

 @(#) $Id: sls_sltc.h,v 0.7.2.5 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_STLC_H__
#define __SLS_STLC_H__

/*
 *  Referenced functions.
 */

static inline void lk_mgmt_sltc_slt_failed(lk_t *lk);
static inline void lk_mgmt_sltc_sslt_failed(lk_t *lk);
static inline void lk_mgmt_sltc_sslt_successful(lk_t *lk);

/* link set and link functions */

static inline void lk_hmrt_sltc_signalling_link_test_ack(lk_t *lk, mblk_t *mp); /* to remote L3 */
static inline void lk_hmrt_sltc_signalling_link_test_msg(lk_t *lk, mblk_t *mp); /* to remote L3 */

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

/*
 *  Forward declarations.
 */

static inline void lk_tt1_timeout(lk_t *lk);

static inline void lk_sltc_hmdt_signalling_link_test_ack(lk_t *lk, mblk_t *mp);         /* from remote L3 */
static inline void lk_sltc_hmdt_signalling_link_test_ack_special(lk_t *lk, mblk_t *mp); /* from remote L3 */
static inline void lk_sltc_hmdt_signalling_link_test_msg(lk_t *lk, mblk_t *mp);         /* from remote L3 */
static inline void lk_sltc_hmdt_signalling_link_test_msg_special(lk_t *lk, mblk_t *mp); /* from remote L3 */

static inline void lk_sltc_lsac_start(lk_t *lk);

static inline void lk_sltc_mgmt_start(lk_t *lk);

/*
 *  Message building functions.
 */

static inline mblk_t *__msg_alloc(mblk_t *mp)
{
    if ( mp ) return mp;
    /* FIXME: make me allocate */
    return mp;
}

static inline void lk_sltc_send_signalling_link_test_msg(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_SLTM;
    p->sltm.mh.ni     = ls->config.ni;
    p->sltm.mh.mp     = 0x3;
    p->sltm.mh.si     = 0x1;
    p->sltm.mh.rl.dpc = ls->config.apc;
    p->sltm.mh.rl.opc = ls->config.lpc;
    p->sltm.mh.rl.sls = lk->config.slc;
    p->sltm.slc       = lk->config.slc;
    p->sltm.tli       = lk->statem.tli;
    bcopy(lk->statem.tmsx, p->sltm.tmsx, p->sltm.tli);
    lk_hmrt_sltc_signalling_link_test_msg(lk, mp);
}

static inline void lk_sltc_send_signalling_link_test_msg_special(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_SSLTM;
    p->sltm.mh.ni     = ls->config.ni;
    p->sltm.mh.mp     = 0x3;
    p->sltm.mh.si     = 0x2;
    p->sltm.mh.rl.dpc = ls->config.apc;
    p->sltm.mh.rl.opc = ls->config.lpc;
    p->sltm.mh.rl.sls = lk->config.slc;
    p->sltm.slc       = lk->config.slc;
    p->sltm.tli       = lk->statem.tli;
    bcopy(lk->statem.tmsx, p->sltm.tmsx, p->sltm.tli);
    lk_hmrt_sltc_signalling_link_test_msg(lk, mp);
}

static inline void lk_sltc_send_signalling_link_test_ack(lk_t *lk, mblk_t *mp)
{
    ls_t *ls = lk->module;
    ls_prim_t *p = (ls_prim_t *)mp->b_rptr;
    if (!mp) return;
    p->primitive      = LS_MESSAGE_FOR_ROUTING_IND;
    p->sig.signal     = LS_SIGNAL_SLTA;
    p->slta.mh.rl.dpc = ls->config.apc;
    p->slta.mh.rl.opc = ls->config.lpc;
    lk_hmrt_sltc_signalling_link_test_ack(lk, mp);
}

static inline void lk_sltc_send_signalling_link_test_ack_special(lk_t *lk, mblk_t *mp)
{
    ls_t *ls = lk->module;
    ls_prim_t *p = (ls_prim_t *)mp->b_rptr;
    if (!mp) return;
    p->primitive      = LS_MESSAGE_FOR_ROUTING_IND;
    p->sig.signal     = LS_SIGNAL_SSLTA;
    p->slta.mh.rl.dpc = ls->config.apc;
    p->slta.mh.rl.opc = ls->config.lpc;
    lk_hmrt_sltc_signalling_link_test_ack(lk, mp);
}

/*
 *  Signalling Link Test Control (SLTC)
 *  Figure 2/Q.707
 */

static inline void lk_tt1_timeout(lk_t *lk)
{
    switch ( lk->statem.sltc_state ) {
        case LK_STATE_1ST_ATTEMPT:
            lk_sltc_send_signalling_link_test_msg(lk, NULL);
            lk_timer_start(tt1);
            lk->statem.sltc_state = LK_STATE_2ND_ATTEMPT;
            break;
        case LK_STATE_2ND_ATTEMPT:
            lk_mgmt_sltc_slt_failed(lk);
            lk_lsac_sltc_slt_failed(lk);
            lk->statem.sltc_state = LK_STATE_IDLE;
            break;
    }
}

static inline void lk_sltc_hmdt_signalling_link_test_msg(lk_t *lk, mblk_t *mp)
{
    switch ( lk->statem.sltc_state ) {
        case LK_STATE_IDLE:
        case LK_STATE_1ST_ATTEMPT:
        case LK_STATE_2ND_ATTEMPT:
            lk_sltc_send_signalling_link_test_ack(lk, mp);
            break;
    }
}

static inline void lk_sltc_mgmt_start(lk_t *lk)
{
    switch ( lk->statem.sltc_state ) {
        case LK_STATE_IDLE:
            lk_sltc_send_signalling_link_test_msg(lk, NULL);
            lk_timer_start(tt1);
            lk->statem.sltc_state = LK_STATE_1ST_ATTEMPT;
            break;
    }
}

static inline void lk_sltc_lsac_start(lk_t *lk)
{
    switch ( lk->statem.sltc_state ) {
        case LK_STATE_IDLE:
            lk_sltc_send_signalling_link_test_msg(lk, NULL);
            lk_timer_start(tt1);
            lk->statem.sltc_state = LK_STATE_1ST_ATTEMPT;
            break;
    }
}

static inline int __compare_test_pattern(lk_t *lk, mblk_t *mp)
{
    int i;
    ls_t *ls = lk->module;
    ls_prim_t *p = (ls_prim_t *)mp->b_rptr;

    if ( lk->statem.tli != p->sltc.tli ) return 0;
    for ( i=0; i<lk->statem.tli; i++ )
        if ( lk->statem.tmsx[i] != p->sltc.tmsx[i] ) return 0;
    if ( &ls->device[p->sltc.mh.rl.sls] != &ls->device[p->sltc.slc] ) return 0;
    if ( ls->config.apc != p->sltc.mh.rl.opc ) return 0;
    return 1;

}

static inline void lk_sltc_hmdt_signalling_link_test_ack(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    switch ( lk->statem.sltc_state ) {
        case LK_STATE_1ST_ATTEMPT:
            lk_timer_stop(tt1);
            if ( !__compare_test_pattern(lk, mp) ) {
                lk_sltc_send_signalling_link_test_msg(lk, mp);
                lk_timer_start(tt1);
                lk->statem.sltc_state = LK_STATE_2ND_ATTEMPT;
            } else {
                lk_lsac_sltc_slt_successful(lk);
                lk->statem.sltc_state = LK_STATE_IDLE;
                freemsg(mp);
            }
            break;
        case LK_STATE_2ND_ATTEMPT:
            lk_timer_stop(tt1);
            if ( !__compare_test_pattern(lk, mp) ) {
                lk_mgmt_sltc_slt_failed(lk);
                lk_lsac_sltc_slt_failed(lk);
                lk->statem.sltc_state = LK_STATE_IDLE;
            } else {
                lk_lsac_sltc_slt_successful(lk);
                lk->statem.sltc_state = LK_STATE_IDLE;
                freemsg(mp);
            }
    }
}

static inline void lk_sltc_hmdt_signalling_link_test_msg_special(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    lk_sltc_send_signalling_link_test_ack_special(lk, mp);
}

static inline void lk_sltc_hmdt_signalling_link_test_ack_special(lk_t *lk, mblk_t *mp) /* from remote L3 */
{
    if ( !__compare_test_pattern(lk, mp) )
        lk_mgmt_sltc_sslt_failed(lk);
    else
        lk_mgmt_sltc_sslt_successful(lk);
    freemsg(mp);
}

#endif  __SLS_STLC_H__

