Sync usage with man page.
[netbsd-mini2440.git] / usr.sbin / isdn / isdnd / fsm.c
blob2d3f075909a53cedd03b2422980bc962d8664745
1 /*
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
6 * are met:
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
23 * SUCH DAMAGE.
25 *---------------------------------------------------------------------------
27 * FSM for isdnd
28 * -------------
30 * $Id: fsm.c,v 1.8 2009/04/16 05:56:32 lukem Exp $
32 * $FreeBSD$
34 * last edit-date: [Mon Dec 13 21:46:07 1999]
36 *---------------------------------------------------------------------------*/
38 #include "isdnd.h"
40 /* table of state descriptions */
42 static const char *state_text[N_STATES] = {
43 "idle",
44 "dialing",
45 "waitdialretry",
46 "dialretry",
48 "pcb-dialing",
49 "pcb-dialfail",
50 "pcb-waitcall",
52 "acb-waitdisc",
53 "acb-waitdial",
54 "acb-dialing",
55 "acb-dialfail",
57 "accepted",
58 "connected",
59 "waitdisconnect",
60 "down",
61 "alert",
63 "Illegal State"
66 /* table of event descriptions */
68 static const char *event_text[N_EVENTS] = {
70 /* incoming messages */
72 "msg-con-ind",
73 "msg-con-act-ind",
74 "msg-disc-ind",
75 "msg-dialout",
77 /* local events */
79 "timeout",
80 "disconnect-req",
81 "callback-req",
82 "alert-req",
84 /* illegal */
86 "Illegal Event"
89 /*---------------------------------------------------------------------------*
90 * illegal state default action
91 *---------------------------------------------------------------------------*/
92 static void
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 *---------------------------------------------------------------------------*/
101 static void
102 F_NcNa(struct cfg_entry *cep)
106 /*---------------------------------------------------------------------------*
107 * incoming CONNECT, accepting call
108 *---------------------------------------------------------------------------*/
109 static void
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 *---------------------------------------------------------------------------*/
120 static void
121 F_MCAI(struct cfg_entry *cep)
123 DBGL(DL_STATE, (logit(LL_DBG, "F_MCAI: Connection active!")));
125 stop_timer(cep);
127 if ((cep->dialin_reaction == REACT_ANSWER) &&
128 (cep->b1protocol == BPROT_NONE))
130 exec_answer(cep);
134 /*---------------------------------------------------------------------------*
135 * timeout
136 *---------------------------------------------------------------------------*/
137 static void
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 *---------------------------------------------------------------------------*/
148 static void
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 *---------------------------------------------------------------------------*/
158 static void
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 *---------------------------------------------------------------------------*/
168 static void
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 *---------------------------------------------------------------------------*/
178 static void
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;
186 cep->dial_count = 0;
188 select_first_dialno(cep);
190 sendm_connect_req(cep);
193 /*---------------------------------------------------------------------------*
194 * outgoing dial successful
195 *---------------------------------------------------------------------------*/
196 static void
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 *---------------------------------------------------------------------------*/
206 static void
207 F_DFL(struct cfg_entry *cep)
209 cep->last_release_time = time(NULL);
211 if (cep->dialouttype == DIALOUT_NORMAL)
213 cep->dial_count++;
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;
223 return;
226 /* retries exhausted */
228 if (!cep->usedown)
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;
233 cep->dial_count = 0;
234 cep->state = ST_IDLE;
235 return;
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);
247 if_down(cep);
248 cep->state = ST_DOWN;
250 else
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;
258 cep->dial_count = 0;
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 *---------------------------------------------------------------------------*/
272 static void
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;
280 cep->dial_count = 0;
282 cep->cdid = CDID_RESERVED;
285 /*---------------------------------------------------------------------------*
286 * active callback dialout retry (ST_SUSE !!!)
287 *---------------------------------------------------------------------------*/
288 static void
289 F_ACBR(struct cfg_entry *cep)
291 cep->dial_count++;
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;
301 return;
304 /* retries exhausted */
306 if (!cep->usedown)
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;
311 cep->dial_count = 0;
312 cep->state = ST_IDLE;
313 return;
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);
325 if_down(cep);
326 cep->state = ST_DOWN;
328 else
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;
336 cep->dial_count = 0;
337 cep->cdid = CDID_RESERVED;
340 /*---------------------------------------------------------------------------*
341 * local requested to send ALERT message
342 *---------------------------------------------------------------------------*/
343 static void
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 *---------------------------------------------------------------------------*/
356 struct state_tab {
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 /* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
363 /* messages */
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}},
369 /* local requests */
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}},
375 /* illegal */
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 /*---------------------------------------------------------------------------*
381 * event handler
382 *---------------------------------------------------------------------------*/
383 void
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]",
422 event_text[event],
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])));
433 else
435 cep->state = newstate;
439 /*---------------------------------------------------------------------------*
440 * return pointer to current state description
441 *---------------------------------------------------------------------------*/
442 const char *
443 printstate(struct cfg_entry *cep)
445 return(state_text[cep->state]);
448 /* EOF */