diff options
Diffstat (limited to 'usr.sbin/i4b/isdnd/fsm.c')
-rw-r--r-- | usr.sbin/i4b/isdnd/fsm.c | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/usr.sbin/i4b/isdnd/fsm.c b/usr.sbin/i4b/isdnd/fsm.c new file mode 100644 index 0000000..13d5778 --- /dev/null +++ b/usr.sbin/i4b/isdnd/fsm.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * FSM for isdnd + * ------------- + * + * $Id: fsm.c,v 1.15 1998/12/05 18:03:12 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:07:31 1998] + * + *---------------------------------------------------------------------------*/ + +#include "isdnd.h" + +/* table of state descriptions */ + +static char *state_text[N_STATES] = { + "idle", + "dialing", + "waitdialretry", + "dialretry", + + "pcb-dialing", + "pcb-dialfail", + "pcb-waitcall", + + "acb-waitdisc", + "acb-waitdial", + "acb-dialing", + "acb-dialfail", + + "accepted", + "connected", + "waitdisconnect", + "down", + "alert", + + "Illegal State" +}; + +/* table of event descriptions */ + +static char *event_text[N_EVENTS] = { + + /* incoming messages */ + + "msg-con-ind", + "msg-con-act-ind", + "msg-disc-ind", + "msg-dialout", + + /* local events */ + + "timeout", + "disconnect-req", + "callback-req", + "alert-req", + + /* illegal */ + + "Illegal Event" +}; + +/*---------------------------------------------------------------------------* + * illegal state default action + *---------------------------------------------------------------------------*/ +static void +F_ill(cfg_entry_t *cep) +{ + DBGL(DL_STATE, (log(LL_DBG, "F_ill: Illegal State reached !!!"))); +} + +/*---------------------------------------------------------------------------* + * No change, No action + *---------------------------------------------------------------------------*/ +static void +F_NcNa(cfg_entry_t *cep) +{ +} + +/*---------------------------------------------------------------------------* + * incoming CONNECT, accepting call + *---------------------------------------------------------------------------*/ +static void +F_MCI(cfg_entry_t *cep) +{ + DBGL(DL_STATE, (log(LL_DBG, "F_MCI: tx SETUP_RESP_ACCEPT"))); + sendm_connect_resp(cep, cep->cdid, SETUP_RESP_ACCEPT, 0); + start_timer(cep, TIMEOUT_CONNECT_ACTIVE); +} + +/*---------------------------------------------------------------------------* + * incoming connect active, call is now active + *---------------------------------------------------------------------------*/ +static void +F_MCAI(cfg_entry_t *cep) +{ + DBGL(DL_STATE, (log(LL_DBG, "F_MCAI: Connection active!"))); + + stop_timer(cep); + + if((cep->dialin_reaction == REACT_ANSWER) && + (cep->b1protocol == BPROT_NONE)) + { + exec_answer(cep); + } +} + +/*---------------------------------------------------------------------------* + * timeout + *---------------------------------------------------------------------------*/ +static void +F_TIMO(cfg_entry_t *cep) +{ + DBGL(DL_STATE, (log(LL_DBG, "F_TIMO: Timout occured!"))); + sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); + cep->cdid = CDID_UNUSED; +} + +/*---------------------------------------------------------------------------* + * incoming disconnect indication + *---------------------------------------------------------------------------*/ +static void +F_IDIS(cfg_entry_t *cep) +{ + DBGL(DL_STATE, (log(LL_DBG, "F_IDIS: disconnect indication"))); + cep->cdid = CDID_UNUSED; +} + +/*---------------------------------------------------------------------------* + * local disconnect request + *---------------------------------------------------------------------------*/ +static void +F_DRQ(cfg_entry_t *cep) +{ + DBGL(DL_STATE, (log(LL_DBG, "F_DRQ: local disconnect request"))); + sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); +} + +/*---------------------------------------------------------------------------* + * disconnect indication after local disconnect req + *---------------------------------------------------------------------------*/ +static void +F_MDI(cfg_entry_t *cep) +{ + DBGL(DL_STATE, (log(LL_DBG, "F_MDI: disconnect indication, local disconnected"))); + cep->cdid = CDID_UNUSED; +} + +/*---------------------------------------------------------------------------* + * local requested outgoing dial + *---------------------------------------------------------------------------*/ +static void +F_DIAL(cfg_entry_t *cep) +{ + DBGL(DL_STATE, (log(LL_DBG, "F_DIAL: local dial out request"))); + + if(cep->dialrandincr) + cep->randomtime = (random() & RANDOM_MASK) + cep->recoverytime; + + cep->dial_count = 0; + + select_first_dialno(cep); + + sendm_connect_req(cep); +} + +/*---------------------------------------------------------------------------* + * outgoing dial successfull + *---------------------------------------------------------------------------*/ +static void +F_DOK(cfg_entry_t *cep) +{ + DBGL(DL_STATE, (log(LL_DBG, "F_DOK: dial out ok"))); + select_this_dialno(cep); +} + +/*---------------------------------------------------------------------------* + * outgoing dial fail (ST_SUSE !!!) + *---------------------------------------------------------------------------*/ +static void +F_DFL(cfg_entry_t *cep) +{ + cep->last_release_time = time(NULL); + + if(cep->dialouttype == DIALOUT_NORMAL) + { + cep->dial_count++; + + if(cep->dial_count < cep->dialretries) + { + /* inside normal retry cycle */ + + DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial fail, dial retry"))); + select_next_dialno(cep); + cep->cdid = CDID_RESERVED; + cep->state = ST_DIALRTMRCHD; + return; + } + + /* retries exhausted */ + + if(!cep->usedown) + { + DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial retry fail, dial retries exhausted"))); + dialresponse(cep, DSTAT_TFAIL); + cep->cdid = CDID_UNUSED; + cep->dial_count = 0; + cep->state = ST_IDLE; + return; + } + + /* interface up/down active */ + + cep->down_retry_count++; + + if(cep->down_retry_count > cep->downtries) + { + /* set interface down */ + DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial retry cycle fail, setting interface down!"))); + dialresponse(cep, DSTAT_PFAIL); + if_down(cep); + cep->state = ST_DOWN; + } + else + { + /* enter new dial retry cycle */ + DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial retry cycle fail, enter new retry cycle!"))); + select_next_dialno(cep); + cep->state = ST_DIALRTMRCHD; + } + + cep->dial_count = 0; + cep->cdid = CDID_RESERVED; + } + else /* cdp->dialouttype == DIALOUT_CALLEDBACK */ + { + DBGL(DL_STATE, (log(LL_DBG, "F_DFL: calledback dial done, wait for incoming call"))); + cep->cdid = CDID_RESERVED; + cep->state = ST_PCB_WAITCALL; + } +} + +/*---------------------------------------------------------------------------* + * local requested outgoing dial + *---------------------------------------------------------------------------*/ +static void +F_ACBW(cfg_entry_t *cep) +{ + DBGL(DL_STATE, (log(LL_DBG, "F_ACBW: local callback, wait callback recovery time"))); + + if(cep->dialrandincr) + cep->randomtime = (random() & RANDOM_MASK) + cep->recoverytime; + + cep->dial_count = 0; + + cep->cdid = CDID_RESERVED; +} + +/*---------------------------------------------------------------------------* + * active callback dialout retry (ST_SUSE !!!) + *---------------------------------------------------------------------------*/ +static void +F_ACBR(cfg_entry_t *cep) +{ + cep->dial_count++; + + if(cep->dial_count < cep->dialretries) + { + /* inside normal retry cycle */ + + DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial fail, dial retry"))); + select_next_dialno(cep); + cep->cdid = CDID_RESERVED; + cep->state = ST_ACB_DIALFAIL; + return; + } + + /* retries exhausted */ + + if(!cep->usedown) + { + DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial retry fail, dial retries exhausted"))); + dialresponse(cep, DSTAT_TFAIL); + cep->cdid = CDID_UNUSED; + cep->dial_count = 0; + cep->state = ST_IDLE; + return; + } + + /* interface up/down active */ + + cep->down_retry_count++; + + if(cep->down_retry_count > cep->downtries) + { + /* set interface down */ + DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial retry cycle fail, setting interface down!"))); + dialresponse(cep, DSTAT_PFAIL); + if_down(cep); + cep->state = ST_DOWN; + } + else + { + /* enter new dial retry cycle */ + DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial retry cycle fail, enter new retry cycle!"))); + select_next_dialno(cep); + cep->state = ST_ACB_DIALFAIL; + } + + cep->dial_count = 0; + cep->cdid = CDID_RESERVED; +} + +/*---------------------------------------------------------------------------* + * local requested to send ALERT message + *---------------------------------------------------------------------------*/ +static void +F_ALRT(cfg_entry_t *cep) +{ + DBGL(DL_STATE, (log(LL_DBG, "F_ALRT: local send alert request"))); + + cep->alert_time = cep->alert; + + sendm_alert_req(cep); +} + +/*---------------------------------------------------------------------------* + * isdn daemon state transition table + *---------------------------------------------------------------------------*/ +struct state_tab { + void(*func)(cfg_entry_t *cep); /* function to execute */ + int newstate; /* next state */ +} state_tab[N_EVENTS][N_STATES] = { + +/* STATE: ST_IDLE ST_DIAL ST_DIALRTMRCHD ST_DIALRETRY ST_PCB_DIAL ST_PCB_DIALFAIL ST_PCB_WAITCALL ST_ACB_WAITDISC ST_ACB_WAITDIAL ST_ACB_DIAL ST_ACB_DIALFAIL ST_ACCEPTED ST_CONNECTED ST_WAITDISCI ST_DOWN ST_ALERT ST_ILLEGAL */ +/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* messages */ +/* EV_MCI */{{F_MCI, ST_ACCEPTED}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_MCI, ST_ACCEPTED}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_MCI, ST_ACCEPTED}, {F_ill, ST_ILL}}, +/* EV_MCAI */{{F_ill, ST_ILL}, {F_DOK, ST_CONNECTED}, {F_ill, ST_ILL}, {F_DOK, ST_CONNECTED}, {F_DOK, ST_CONNECTED}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_DOK, ST_CONNECTED}, {F_ill, ST_ILL}, {F_MCAI,ST_CONNECTED}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}, +/* EV_MDI */{{F_ill, ST_ILL}, {F_DFL, ST_SUSE}, {F_ill, ST_ILL}, {F_DFL, ST_SUSE}, {F_DFL, ST_SUSE}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ACBW,ST_ACB_WAITDIAL},{F_ill, ST_ILL}, {F_ACBR, ST_SUSE}, {F_ACBR,ST_SUSE}, {F_IDIS,ST_IDLE}, {F_IDIS,ST_IDLE}, {F_MDI, ST_IDLE}, {F_ill, ST_ILL}, {F_MDI, ST_IDLE}, {F_ill, ST_ILL}}, +/* EV_MDO */{{F_DIAL,ST_DIAL}, {F_NcNa,ST_DIAL}, {F_NcNa,ST_DIALRTMRCHD},{F_NcNa,ST_DIALRETRY}, {F_NcNa,ST_PCB_DIAL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}, + +/* local requests */ +/* EV_TIMO */{{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_TIMO,ST_IDLE}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}, +/* EV_DRQ */{{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_DRQ, ST_WAITDISCI}, {F_NcNa,ST_WAITDISCI}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}, +/* EV_CBRQ */{{F_NcNa,ST_ACB_WAITDIAL},{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_NcNa,ST_ACB_WAITDIAL},{F_NcNa, ST_ACB_DIAL}, {F_NcNa,ST_ACB_DIALFAIL},{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}, +/* EV_ALRT */{{F_ALRT,ST_ALERT}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}, + +/* illegal */ + +/* EV_ILL */{{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}} +}; + +/*---------------------------------------------------------------------------* + * event handler + *---------------------------------------------------------------------------*/ +void +next_state(cfg_entry_t *cep, int event) +{ + int currstate, newstate; + + if(event > N_EVENTS) + { + log(LL_ERR, "FSM: event > N_EVENTS"); + do_exit(1); + } + + currstate = cep->state; + + if(currstate > N_STATES) + { + log(LL_ERR, "FSM: currstate > N_STATES"); + do_exit(1); + } + + newstate = state_tab[event][currstate].newstate; + + if(newstate > N_STATES) + { + log(LL_ERR, "FSM: newstate > N_STATES"); + do_exit(1); + } + + if(newstate != ST_SUSE) + { + DBGL(DL_STATE, (log(LL_DBG, "FSM event [%s]: [%s => %s]", event_text[event], + state_text[currstate], + state_text[newstate]))); + } + + (*state_tab[event][currstate].func)(cep); + + if(newstate == ST_ILL) + { + log(LL_ERR, "FSM ILLEGAL STATE, event=%s: oldstate=%s => newstate=%s]", + event_text[event], + state_text[currstate], + state_text[newstate]); + } + + if(newstate == ST_SUSE) + { + DBGL(DL_STATE, (log(LL_DBG, "FSM (SUSE) event [%s]: [%s => %s]", event_text[event], + state_text[currstate], + state_text[cep->state]))); + } + else + { + cep->state = newstate; + } +} + +/*---------------------------------------------------------------------------* + * return pointer to current state description + *---------------------------------------------------------------------------*/ +char * +printstate(cfg_entry_t *cep) +{ + return((char *) state_text[cep->state]); +} + +/* EOF */ |