2 * Copyright (c) 1997, 1999 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 * $Id: fsm.c,v 1.8 2009/04/16 05:56:32 lukem Exp $
34 * last edit-date: [Mon Dec 13 21:46:07 1999]
36 *---------------------------------------------------------------------------*/
40 /* table of state descriptions */
42 static const char *state_text
[N_STATES
] = {
66 /* table of event descriptions */
68 static const char *event_text
[N_EVENTS
] = {
70 /* incoming messages */
89 /*---------------------------------------------------------------------------*
90 * illegal state default action
91 *---------------------------------------------------------------------------*/
93 F_ill(struct cfg_entry
*cep
)
95 DBGL(DL_STATE
, (logit(LL_DBG
, "F_ill: Illegal State reached !!!")));
98 /*---------------------------------------------------------------------------*
99 * No change, No action
100 *---------------------------------------------------------------------------*/
102 F_NcNa(struct cfg_entry
*cep
)
106 /*---------------------------------------------------------------------------*
107 * incoming CONNECT, accepting call
108 *---------------------------------------------------------------------------*/
110 F_MCI(struct cfg_entry
*cep
)
112 DBGL(DL_STATE
, (logit(LL_DBG
, "F_MCI: tx SETUP_RESP_ACCEPT")));
113 sendm_connect_resp(cep
, cep
->cdid
, SETUP_RESP_ACCEPT
, 0);
114 start_timer(cep
, TIMEOUT_CONNECT_ACTIVE
);
117 /*---------------------------------------------------------------------------*
118 * incoming connect active, call is now active
119 *---------------------------------------------------------------------------*/
121 F_MCAI(struct cfg_entry
*cep
)
123 DBGL(DL_STATE
, (logit(LL_DBG
, "F_MCAI: Connection active!")));
127 if ((cep
->dialin_reaction
== REACT_ANSWER
) &&
128 (cep
->b1protocol
== BPROT_NONE
))
134 /*---------------------------------------------------------------------------*
136 *---------------------------------------------------------------------------*/
138 F_TIMO(struct cfg_entry
*cep
)
140 DBGL(DL_STATE
, (logit(LL_DBG
, "F_TIMO: Timout occurred!")));
141 sendm_disconnect_req(cep
, (CAUSET_I4B
<< 8) | CAUSE_I4B_NORMAL
);
142 cep
->cdid
= CDID_UNUSED
;
145 /*---------------------------------------------------------------------------*
146 * incoming disconnect indication
147 *---------------------------------------------------------------------------*/
149 F_IDIS(struct cfg_entry
*cep
)
151 DBGL(DL_STATE
, (logit(LL_DBG
, "F_IDIS: disconnect indication")));
152 cep
->cdid
= CDID_UNUSED
;
155 /*---------------------------------------------------------------------------*
156 * local disconnect request
157 *---------------------------------------------------------------------------*/
159 F_DRQ(struct cfg_entry
*cep
)
161 DBGL(DL_STATE
, (logit(LL_DBG
, "F_DRQ: local disconnect request")));
162 sendm_disconnect_req(cep
, (CAUSET_I4B
<< 8) | CAUSE_I4B_NORMAL
);
165 /*---------------------------------------------------------------------------*
166 * disconnect indication after local disconnect req
167 *---------------------------------------------------------------------------*/
169 F_MDI(struct cfg_entry
*cep
)
171 DBGL(DL_STATE
, (logit(LL_DBG
, "F_MDI: disconnect indication, local disconnected")));
172 cep
->cdid
= CDID_UNUSED
;
175 /*---------------------------------------------------------------------------*
176 * local requested outgoing dial
177 *---------------------------------------------------------------------------*/
179 F_DIAL(struct cfg_entry
*cep
)
181 DBGL(DL_STATE
, (logit(LL_DBG
, "F_DIAL: local dial out request")));
183 if (cep
->dialrandincr
)
184 cep
->randomtime
= (random() & RANDOM_MASK
) + cep
->recoverytime
;
188 select_first_dialno(cep
);
190 sendm_connect_req(cep
);
193 /*---------------------------------------------------------------------------*
194 * outgoing dial successful
195 *---------------------------------------------------------------------------*/
197 F_DOK(struct cfg_entry
*cep
)
199 DBGL(DL_STATE
, (logit(LL_DBG
, "F_DOK: dial out ok")));
200 select_this_dialno(cep
);
203 /*---------------------------------------------------------------------------*
204 * outgoing dial fail (ST_SUSE !!!)
205 *---------------------------------------------------------------------------*/
207 F_DFL(struct cfg_entry
*cep
)
209 cep
->last_release_time
= time(NULL
);
211 if (cep
->dialouttype
== DIALOUT_NORMAL
)
215 if (cep
->dial_count
< cep
->dialretries
|| cep
->dialretries
== -1) /* Added by FST <mailto:fsteevie@dds.nl> for unlimited dialing (sorry, but I needed it) */
217 /* inside normal retry cycle */
219 DBGL(DL_STATE
, (logit(LL_DBG
, "F_DFL: dial fail, dial retry")));
220 select_next_dialno(cep
);
221 cep
->cdid
= CDID_RESERVED
;
222 cep
->state
= ST_DIALRTMRCHD
;
226 /* retries exhausted */
230 DBGL(DL_STATE
, (logit(LL_DBG
, "F_DFL: dial retry fail, dial retries exhausted")));
231 dialresponse(cep
, DSTAT_TFAIL
);
232 cep
->cdid
= CDID_UNUSED
;
234 cep
->state
= ST_IDLE
;
238 /* interface up/down active */
240 cep
->down_retry_count
++;
242 if (cep
->down_retry_count
> cep
->downtries
)
244 /* set interface down */
245 DBGL(DL_STATE
, (logit(LL_DBG
, "F_DFL: dial retry cycle fail, setting interface down!")));
246 dialresponse(cep
, DSTAT_PFAIL
);
248 cep
->state
= ST_DOWN
;
252 /* enter new dial retry cycle */
253 DBGL(DL_STATE
, (logit(LL_DBG
, "F_DFL: dial retry cycle fail, enter new retry cycle!")));
254 select_next_dialno(cep
);
255 cep
->state
= ST_DIALRTMRCHD
;
259 cep
->cdid
= CDID_RESERVED
;
261 else /* cdp->dialouttype == DIALOUT_CALLEDBACK */
263 DBGL(DL_STATE
, (logit(LL_DBG
, "F_DFL: calledback dial done, wait for incoming call")));
264 cep
->cdid
= CDID_RESERVED
;
265 cep
->state
= ST_PCB_WAITCALL
;
269 /*---------------------------------------------------------------------------*
270 * local requested outgoing dial
271 *---------------------------------------------------------------------------*/
273 F_ACBW(struct cfg_entry
*cep
)
275 DBGL(DL_STATE
, (logit(LL_DBG
, "F_ACBW: local callback, wait callback recovery time")));
277 if (cep
->dialrandincr
)
278 cep
->randomtime
= (random() & RANDOM_MASK
) + cep
->recoverytime
;
282 cep
->cdid
= CDID_RESERVED
;
285 /*---------------------------------------------------------------------------*
286 * active callback dialout retry (ST_SUSE !!!)
287 *---------------------------------------------------------------------------*/
289 F_ACBR(struct cfg_entry
*cep
)
293 if (cep
->dial_count
< cep
->dialretries
|| cep
->dialretries
== -1) /* Added by FST <mailto:fsteevie@dds.nl> for unlimited dialing (sorry, but I needed it) */
295 /* inside normal retry cycle */
297 DBGL(DL_STATE
, (logit(LL_DBG
, "F_ACBR: dial fail, dial retry")));
298 select_next_dialno(cep
);
299 cep
->cdid
= CDID_RESERVED
;
300 cep
->state
= ST_ACB_DIALFAIL
;
304 /* retries exhausted */
308 DBGL(DL_STATE
, (logit(LL_DBG
, "F_ACBR: dial retry fail, dial retries exhausted")));
309 dialresponse(cep
, DSTAT_TFAIL
);
310 cep
->cdid
= CDID_UNUSED
;
312 cep
->state
= ST_IDLE
;
316 /* interface up/down active */
318 cep
->down_retry_count
++;
320 if (cep
->down_retry_count
> cep
->downtries
)
322 /* set interface down */
323 DBGL(DL_STATE
, (logit(LL_DBG
, "F_ACBR: dial retry cycle fail, setting interface down!")));
324 dialresponse(cep
, DSTAT_PFAIL
);
326 cep
->state
= ST_DOWN
;
330 /* enter new dial retry cycle */
331 DBGL(DL_STATE
, (logit(LL_DBG
, "F_ACBR: dial retry cycle fail, enter new retry cycle!")));
332 select_next_dialno(cep
);
333 cep
->state
= ST_ACB_DIALFAIL
;
337 cep
->cdid
= CDID_RESERVED
;
340 /*---------------------------------------------------------------------------*
341 * local requested to send ALERT message
342 *---------------------------------------------------------------------------*/
344 F_ALRT(struct cfg_entry
*cep
)
346 DBGL(DL_STATE
, (logit(LL_DBG
, "F_ALRT: local send alert request")));
348 cep
->alert_time
= cep
->alert
;
350 sendm_alert_req(cep
);
353 /*---------------------------------------------------------------------------*
354 * isdn daemon state transition table
355 *---------------------------------------------------------------------------*/
357 void(*func
)(struct cfg_entry
*cep
); /* function to execute */
358 int newstate
; /* next state */
359 } state_tab
[N_EVENTS
][N_STATES
] = {
361 /* 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 */
362 /* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
364 /* 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
}},
365 /* 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
}},
366 /* 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
}},
367 /* 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
}},
370 /* 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
}},
371 /* 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
}},
372 /* 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
}},
373 /* 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
}},
377 /* 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
}}
380 /*---------------------------------------------------------------------------*
382 *---------------------------------------------------------------------------*/
384 next_state(struct cfg_entry
*cep
, int event
)
386 int currstate
, newstate
;
388 if (event
>= N_EVENTS
)
390 logit(LL_ERR
, "next_state: event > N_EVENTS");
391 error_exit(1, "next_state: event > N_EVENTS");
394 currstate
= cep
->state
;
396 if (currstate
>= N_STATES
)
398 logit(LL_ERR
, "next_state: currstate > N_STATES");
399 error_exit(1, "next_state: currstate > N_STATES");
402 newstate
= state_tab
[event
][currstate
].newstate
;
404 if (newstate
>= N_STATES
)
406 logit(LL_ERR
, "next_state: newstate > N_STATES");
407 error_exit(1, "next_state: newstate > N_STATES");
410 if (newstate
!= ST_SUSE
)
412 DBGL(DL_STATE
, (logit(LL_DBG
, "FSM event [%s]: [%s => %s]", event_text
[event
],
413 state_text
[currstate
],
414 state_text
[newstate
])));
417 (*state_tab
[event
][currstate
].func
)(cep
);
419 if (newstate
== ST_ILL
)
421 logit(LL_ERR
, "FSM ILLEGAL STATE, event=%s: oldstate=%s => newstate=%s]",
423 state_text
[currstate
],
424 state_text
[newstate
]);
427 if (newstate
== ST_SUSE
)
429 DBGL(DL_STATE
, (logit(LL_DBG
, "FSM (SUSE) event [%s]: [%s => %s]", event_text
[event
],
430 state_text
[currstate
],
431 state_text
[cep
->state
])));
435 cep
->state
= newstate
;
439 /*---------------------------------------------------------------------------*
440 * return pointer to current state description
441 *---------------------------------------------------------------------------*/
443 printstate(struct cfg_entry
*cep
)
445 return(state_text
[cep
->state
]);