2 * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 *---------------------------------------------------------------------------
30 * $FreeBSD: src/usr.sbin/i4b/isdnd/fsm.c,v 1.6.2.2 2001/08/10 23:11:14 obrien Exp $
32 * last edit-date: [Sat Jul 21 18:25:48 2001]
34 *---------------------------------------------------------------------------*/
38 /* table of state descriptions */
40 static char *state_text[N_STATES] = {
64 /* table of event descriptions */
66 static char *event_text[N_EVENTS] = {
68 /* incoming messages */
87 /*---------------------------------------------------------------------------*
88 * illegal state default action
89 *---------------------------------------------------------------------------*/
91 F_ill(cfg_entry_t *cep)
93 DBGL(DL_STATE, (log(LL_DBG, "F_ill: Illegal State reached !!!")));
96 /*---------------------------------------------------------------------------*
97 * No change, No action
98 *---------------------------------------------------------------------------*/
100 F_NcNa(cfg_entry_t *cep)
104 /*---------------------------------------------------------------------------*
105 * incoming CONNECT, accepting call
106 *---------------------------------------------------------------------------*/
108 F_MCI(cfg_entry_t *cep)
110 DBGL(DL_STATE, (log(LL_DBG, "F_MCI: tx SETUP_RESP_ACCEPT")));
111 sendm_connect_resp(cep, cep->cdid, SETUP_RESP_ACCEPT, 0);
112 start_timer(cep, TIMEOUT_CONNECT_ACTIVE);
115 /*---------------------------------------------------------------------------*
116 * incoming connect active, call is now active
117 *---------------------------------------------------------------------------*/
119 F_MCAI(cfg_entry_t *cep)
121 DBGL(DL_STATE, (log(LL_DBG, "F_MCAI: Connection active!")));
125 if((cep->dialin_reaction == REACT_ANSWER) &&
126 (cep->b1protocol == BPROT_NONE))
132 /*---------------------------------------------------------------------------*
134 *---------------------------------------------------------------------------*/
136 F_TIMO(cfg_entry_t *cep)
138 DBGL(DL_STATE, (log(LL_DBG, "F_TIMO: Timout occured!")));
139 sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
140 cep->cdid = CDID_UNUSED;
143 /*---------------------------------------------------------------------------*
144 * incoming disconnect indication
145 *---------------------------------------------------------------------------*/
147 F_IDIS(cfg_entry_t *cep)
149 DBGL(DL_STATE, (log(LL_DBG, "F_IDIS: disconnect indication")));
150 cep->cdid = CDID_UNUSED;
153 /*---------------------------------------------------------------------------*
154 * local disconnect request
155 *---------------------------------------------------------------------------*/
157 F_DRQ(cfg_entry_t *cep)
159 DBGL(DL_STATE, (log(LL_DBG, "F_DRQ: local disconnect request")));
160 sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
163 /*---------------------------------------------------------------------------*
164 * disconnect indication after local disconnect req
165 *---------------------------------------------------------------------------*/
167 F_MDI(cfg_entry_t *cep)
169 DBGL(DL_STATE, (log(LL_DBG, "F_MDI: disconnect indication, local disconnected")));
170 cep->cdid = CDID_UNUSED;
173 /*---------------------------------------------------------------------------*
174 * local requested outgoing dial
175 *---------------------------------------------------------------------------*/
177 F_DIAL(cfg_entry_t *cep)
179 DBGL(DL_STATE, (log(LL_DBG, "F_DIAL: local dial out request")));
181 if(cep->dialrandincr)
182 cep->randomtime = (random() & RANDOM_MASK) + cep->recoverytime;
186 select_first_dialno(cep);
188 sendm_connect_req(cep);
191 /*---------------------------------------------------------------------------*
192 * outgoing dial successfull
193 *---------------------------------------------------------------------------*/
195 F_DOK(cfg_entry_t *cep)
197 DBGL(DL_STATE, (log(LL_DBG, "F_DOK: dial out ok")));
198 select_this_dialno(cep);
201 /*---------------------------------------------------------------------------*
202 * outgoing dial fail (ST_SUSE !!!)
203 *---------------------------------------------------------------------------*/
205 F_DFL(cfg_entry_t *cep)
207 cep->last_release_time = time(NULL);
209 if(cep->dialouttype == DIALOUT_NORMAL)
213 if(cep->dial_count < cep->dialretries || cep->dialretries == -1) /* Added by FST <mailto:fsteevie@dds.nl> for unlimited dialing (sorry, but I needed it) */
215 /* inside normal retry cycle */
217 DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial fail, dial retry")));
218 select_next_dialno(cep);
219 cep->cdid = CDID_RESERVED;
220 cep->state = ST_DIALRTMRCHD;
224 /* retries exhausted */
228 DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial retry fail, dial retries exhausted")));
229 dialresponse(cep, DSTAT_TFAIL);
230 cep->cdid = CDID_UNUSED;
232 cep->state = ST_IDLE;
236 /* interface up/down active */
238 cep->down_retry_count++;
240 if(cep->down_retry_count > cep->downtries)
242 /* set interface down */
243 DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial retry cycle fail, setting interface down!")));
244 dialresponse(cep, DSTAT_PFAIL);
246 cep->state = ST_DOWN;
250 /* enter new dial retry cycle */
251 DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial retry cycle fail, enter new retry cycle!")));
252 select_next_dialno(cep);
253 cep->state = ST_DIALRTMRCHD;
257 cep->cdid = CDID_RESERVED;
259 else /* cdp->dialouttype == DIALOUT_CALLEDBACK */
261 DBGL(DL_STATE, (log(LL_DBG, "F_DFL: calledback dial done, wait for incoming call")));
262 cep->cdid = CDID_RESERVED;
263 cep->state = ST_PCB_WAITCALL;
267 /*---------------------------------------------------------------------------*
268 * local requested outgoing dial
269 *---------------------------------------------------------------------------*/
271 F_ACBW(cfg_entry_t *cep)
273 DBGL(DL_STATE, (log(LL_DBG, "F_ACBW: local callback, wait callback recovery time")));
275 if(cep->dialrandincr)
276 cep->randomtime = (random() & RANDOM_MASK) + cep->recoverytime;
280 cep->cdid = CDID_RESERVED;
283 /*---------------------------------------------------------------------------*
284 * active callback dialout retry (ST_SUSE !!!)
285 *---------------------------------------------------------------------------*/
287 F_ACBR(cfg_entry_t *cep)
291 if(cep->dial_count < cep->dialretries || cep->dialretries == -1) /* Added by FST <mailto:fsteevie@dds.nl> for unlimited dialing (sorry, but I needed it) */
293 /* inside normal retry cycle */
295 DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial fail, dial retry")));
296 select_next_dialno(cep);
297 cep->cdid = CDID_RESERVED;
298 cep->state = ST_ACB_DIALFAIL;
302 /* retries exhausted */
306 DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial retry fail, dial retries exhausted")));
307 dialresponse(cep, DSTAT_TFAIL);
308 cep->cdid = CDID_UNUSED;
310 cep->state = ST_IDLE;
314 /* interface up/down active */
316 cep->down_retry_count++;
318 if(cep->down_retry_count > cep->downtries)
320 /* set interface down */
321 DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial retry cycle fail, setting interface down!")));
322 dialresponse(cep, DSTAT_PFAIL);
324 cep->state = ST_DOWN;
328 /* enter new dial retry cycle */
329 DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial retry cycle fail, enter new retry cycle!")));
330 select_next_dialno(cep);
331 cep->state = ST_ACB_DIALFAIL;
335 cep->cdid = CDID_RESERVED;
338 /*---------------------------------------------------------------------------*
339 * local requested to send ALERT message
340 *---------------------------------------------------------------------------*/
342 F_ALRT(cfg_entry_t *cep)
344 DBGL(DL_STATE, (log(LL_DBG, "F_ALRT: local send alert request")));
346 cep->alert_time = cep->alert;
348 sendm_alert_req(cep);
351 /*---------------------------------------------------------------------------*
352 * isdn daemon state transition table
353 *---------------------------------------------------------------------------*/
355 void(*func)(cfg_entry_t *cep); /* function to execute */
356 int newstate; /* next state */
357 } state_tab[N_EVENTS][N_STATES] = {
359 /* 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 */
360 /* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
362 /* 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}},
363 /* 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}},
364 /* 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}},
365 /* 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}},
368 /* 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}},
369 /* EV_DRQ */{{F_NcNa, ST_IDLE}, {F_DRQ, ST_WAITDISCI}, {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_NcNa, ST_DOWN}, {F_ill, ST_ILL}, {F_ill, ST_ILL}},
370 /* 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}},
371 /* 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}},
375 /* 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}}
378 /*---------------------------------------------------------------------------*
380 *---------------------------------------------------------------------------*/
382 next_state(cfg_entry_t *cep, int event)
384 int currstate, newstate;
388 log(LL_ERR, "next_state: event > N_EVENTS");
389 error_exit(1, "next_state: event > N_EVENTS");
392 currstate = cep->state;
394 if(currstate > N_STATES)
396 log(LL_ERR, "next_state: currstate > N_STATES");
397 error_exit(1, "next_state: currstate > N_STATES");
400 newstate = state_tab[event][currstate].newstate;
402 if(newstate > N_STATES)
404 log(LL_ERR, "next_state: newstate > N_STATES");
405 error_exit(1, "next_state: newstate > N_STATES");
408 if(newstate != ST_SUSE)
410 DBGL(DL_STATE, (log(LL_DBG, "FSM event [%s]: [%s => %s]", event_text[event],
411 state_text[currstate],
412 state_text[newstate])));
415 (*state_tab[event][currstate].func)(cep);
417 if(newstate == ST_ILL)
419 log(LL_ERR, "FSM ILLEGAL STATE, event=%s: oldstate=%s => newstate=%s]",
421 state_text[currstate],
422 state_text[newstate]);
425 if(newstate == ST_SUSE)
427 DBGL(DL_STATE, (log(LL_DBG, "FSM (SUSE) event [%s]: [%s => %s]", event_text[event],
428 state_text[currstate],
429 state_text[cep->state])));
433 cep->state = newstate;
437 /*---------------------------------------------------------------------------*
438 * return pointer to current state description
439 *---------------------------------------------------------------------------*/
441 printstate(cfg_entry_t *cep)
443 return((char *) state_text[cep->state]);