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 $
31 * $DragonFly: src/usr.sbin/i4b/isdnd/fsm.c,v 1.3 2007/05/13 18:33:59 swildner Exp $
33 * last edit-date: [Sat Jul 21 18:25:48 2001]
35 *---------------------------------------------------------------------------*/
39 /* table of state descriptions */
41 static char *state_text[N_STATES] = {
65 /* table of event descriptions */
67 static char *event_text[N_EVENTS] = {
69 /* incoming messages */
88 /*---------------------------------------------------------------------------*
89 * illegal state default action
90 *---------------------------------------------------------------------------*/
92 F_ill(cfg_entry_t *cep)
94 DBGL(DL_STATE, (dolog(LL_DBG, "F_ill: Illegal State reached !!!")));
97 /*---------------------------------------------------------------------------*
98 * No change, No action
99 *---------------------------------------------------------------------------*/
101 F_NcNa(cfg_entry_t *cep)
105 /*---------------------------------------------------------------------------*
106 * incoming CONNECT, accepting call
107 *---------------------------------------------------------------------------*/
109 F_MCI(cfg_entry_t *cep)
111 DBGL(DL_STATE, (dolog(LL_DBG, "F_MCI: tx SETUP_RESP_ACCEPT")));
112 sendm_connect_resp(cep, cep->cdid, SETUP_RESP_ACCEPT, 0);
113 start_timer(cep, TIMEOUT_CONNECT_ACTIVE);
116 /*---------------------------------------------------------------------------*
117 * incoming connect active, call is now active
118 *---------------------------------------------------------------------------*/
120 F_MCAI(cfg_entry_t *cep)
122 DBGL(DL_STATE, (dolog(LL_DBG, "F_MCAI: Connection active!")));
126 if((cep->dialin_reaction == REACT_ANSWER) &&
127 (cep->b1protocol == BPROT_NONE))
133 /*---------------------------------------------------------------------------*
135 *---------------------------------------------------------------------------*/
137 F_TIMO(cfg_entry_t *cep)
139 DBGL(DL_STATE, (dolog(LL_DBG, "F_TIMO: Timeout occurred!")));
140 sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
141 cep->cdid = CDID_UNUSED;
144 /*---------------------------------------------------------------------------*
145 * incoming disconnect indication
146 *---------------------------------------------------------------------------*/
148 F_IDIS(cfg_entry_t *cep)
150 DBGL(DL_STATE, (dolog(LL_DBG, "F_IDIS: disconnect indication")));
151 cep->cdid = CDID_UNUSED;
154 /*---------------------------------------------------------------------------*
155 * local disconnect request
156 *---------------------------------------------------------------------------*/
158 F_DRQ(cfg_entry_t *cep)
160 DBGL(DL_STATE, (dolog(LL_DBG, "F_DRQ: local disconnect request")));
161 sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
164 /*---------------------------------------------------------------------------*
165 * disconnect indication after local disconnect req
166 *---------------------------------------------------------------------------*/
168 F_MDI(cfg_entry_t *cep)
170 DBGL(DL_STATE, (dolog(LL_DBG, "F_MDI: disconnect indication, local disconnected")));
171 cep->cdid = CDID_UNUSED;
174 /*---------------------------------------------------------------------------*
175 * local requested outgoing dial
176 *---------------------------------------------------------------------------*/
178 F_DIAL(cfg_entry_t *cep)
180 DBGL(DL_STATE, (dolog(LL_DBG, "F_DIAL: local dial out request")));
182 if(cep->dialrandincr)
183 cep->randomtime = (random() & RANDOM_MASK) + cep->recoverytime;
187 select_first_dialno(cep);
189 sendm_connect_req(cep);
192 /*---------------------------------------------------------------------------*
193 * outgoing dial successfull
194 *---------------------------------------------------------------------------*/
196 F_DOK(cfg_entry_t *cep)
198 DBGL(DL_STATE, (dolog(LL_DBG, "F_DOK: dial out ok")));
199 select_this_dialno(cep);
202 /*---------------------------------------------------------------------------*
203 * outgoing dial fail (ST_SUSE !!!)
204 *---------------------------------------------------------------------------*/
206 F_DFL(cfg_entry_t *cep)
208 cep->last_release_time = time(NULL);
210 if(cep->dialouttype == DIALOUT_NORMAL)
214 if(cep->dial_count < cep->dialretries || cep->dialretries == -1) /* Added by FST <mailto:fsteevie@dds.nl> for unlimited dialing (sorry, but I needed it) */
216 /* inside normal retry cycle */
218 DBGL(DL_STATE, (dolog(LL_DBG, "F_DFL: dial fail, dial retry")));
219 select_next_dialno(cep);
220 cep->cdid = CDID_RESERVED;
221 cep->state = ST_DIALRTMRCHD;
225 /* retries exhausted */
229 DBGL(DL_STATE, (dolog(LL_DBG, "F_DFL: dial retry fail, dial retries exhausted")));
230 dialresponse(cep, DSTAT_TFAIL);
231 cep->cdid = CDID_UNUSED;
233 cep->state = ST_IDLE;
237 /* interface up/down active */
239 cep->down_retry_count++;
241 if(cep->down_retry_count > cep->downtries)
243 /* set interface down */
244 DBGL(DL_STATE, (dolog(LL_DBG, "F_DFL: dial retry cycle fail, setting interface down!")));
245 dialresponse(cep, DSTAT_PFAIL);
247 cep->state = ST_DOWN;
251 /* enter new dial retry cycle */
252 DBGL(DL_STATE, (dolog(LL_DBG, "F_DFL: dial retry cycle fail, enter new retry cycle!")));
253 select_next_dialno(cep);
254 cep->state = ST_DIALRTMRCHD;
258 cep->cdid = CDID_RESERVED;
260 else /* cdp->dialouttype == DIALOUT_CALLEDBACK */
262 DBGL(DL_STATE, (dolog(LL_DBG, "F_DFL: calledback dial done, wait for incoming call")));
263 cep->cdid = CDID_RESERVED;
264 cep->state = ST_PCB_WAITCALL;
268 /*---------------------------------------------------------------------------*
269 * local requested outgoing dial
270 *---------------------------------------------------------------------------*/
272 F_ACBW(cfg_entry_t *cep)
274 DBGL(DL_STATE, (dolog(LL_DBG, "F_ACBW: local callback, wait callback recovery time")));
276 if(cep->dialrandincr)
277 cep->randomtime = (random() & RANDOM_MASK) + cep->recoverytime;
281 cep->cdid = CDID_RESERVED;
284 /*---------------------------------------------------------------------------*
285 * active callback dialout retry (ST_SUSE !!!)
286 *---------------------------------------------------------------------------*/
288 F_ACBR(cfg_entry_t *cep)
292 if(cep->dial_count < cep->dialretries || cep->dialretries == -1) /* Added by FST <mailto:fsteevie@dds.nl> for unlimited dialing (sorry, but I needed it) */
294 /* inside normal retry cycle */
296 DBGL(DL_STATE, (dolog(LL_DBG, "F_ACBR: dial fail, dial retry")));
297 select_next_dialno(cep);
298 cep->cdid = CDID_RESERVED;
299 cep->state = ST_ACB_DIALFAIL;
303 /* retries exhausted */
307 DBGL(DL_STATE, (dolog(LL_DBG, "F_ACBR: dial retry fail, dial retries exhausted")));
308 dialresponse(cep, DSTAT_TFAIL);
309 cep->cdid = CDID_UNUSED;
311 cep->state = ST_IDLE;
315 /* interface up/down active */
317 cep->down_retry_count++;
319 if(cep->down_retry_count > cep->downtries)
321 /* set interface down */
322 DBGL(DL_STATE, (dolog(LL_DBG, "F_ACBR: dial retry cycle fail, setting interface down!")));
323 dialresponse(cep, DSTAT_PFAIL);
325 cep->state = ST_DOWN;
329 /* enter new dial retry cycle */
330 DBGL(DL_STATE, (dolog(LL_DBG, "F_ACBR: dial retry cycle fail, enter new retry cycle!")));
331 select_next_dialno(cep);
332 cep->state = ST_ACB_DIALFAIL;
336 cep->cdid = CDID_RESERVED;
339 /*---------------------------------------------------------------------------*
340 * local requested to send ALERT message
341 *---------------------------------------------------------------------------*/
343 F_ALRT(cfg_entry_t *cep)
345 DBGL(DL_STATE, (dolog(LL_DBG, "F_ALRT: local send alert request")));
347 cep->alert_time = cep->alert;
349 sendm_alert_req(cep);
352 /*---------------------------------------------------------------------------*
353 * isdn daemon state transition table
354 *---------------------------------------------------------------------------*/
356 void(*func)(cfg_entry_t *cep); /* function to execute */
357 int newstate; /* next state */
358 } state_tab[N_EVENTS][N_STATES] = {
360 /* 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 */
361 /* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
363 /* 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}},
364 /* 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}},
365 /* 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}},
366 /* 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}},
369 /* 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}},
370 /* 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}},
371 /* 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}},
372 /* 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}},
376 /* 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}}
379 /*---------------------------------------------------------------------------*
381 *---------------------------------------------------------------------------*/
383 next_state(cfg_entry_t *cep, int event)
385 int currstate, newstate;
389 dolog(LL_ERR, "next_state: event > N_EVENTS");
390 error_exit(1, "next_state: event > N_EVENTS");
393 currstate = cep->state;
395 if(currstate > N_STATES)
397 dolog(LL_ERR, "next_state: currstate > N_STATES");
398 error_exit(1, "next_state: currstate > N_STATES");
401 newstate = state_tab[event][currstate].newstate;
403 if(newstate > N_STATES)
405 dolog(LL_ERR, "next_state: newstate > N_STATES");
406 error_exit(1, "next_state: newstate > N_STATES");
409 if(newstate != ST_SUSE)
411 DBGL(DL_STATE, (dolog(LL_DBG, "FSM event [%s]: [%s => %s]", event_text[event],
412 state_text[currstate],
413 state_text[newstate])));
416 (*state_tab[event][currstate].func)(cep);
418 if(newstate == ST_ILL)
420 dolog(LL_ERR, "FSM ILLEGAL STATE, event=%s: oldstate=%s => newstate=%s]",
422 state_text[currstate],
423 state_text[newstate]);
426 if(newstate == ST_SUSE)
428 DBGL(DL_STATE, (dolog(LL_DBG, "FSM (SUSE) event [%s]: [%s => %s]", event_text[event],
429 state_text[currstate],
430 state_text[cep->state])));
434 cep->state = newstate;
438 /*---------------------------------------------------------------------------*
439 * return pointer to current state description
440 *---------------------------------------------------------------------------*/
442 printstate(cfg_entry_t *cep)
444 return((char *) state_text[cep->state]);