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
]);