Add a manual page explaining the format of /etc/manpath.config.
[dragonfly/vkernel-mp.git] / usr.sbin / i4b / isdnd / fsm.c
blob9e4426d3ef81bb7001549f001b9593f80f3e391e
1 /*
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
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 * $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.2 2003/06/17 06:29:54 dillon Exp $
33 * last edit-date: [Sat Jul 21 18:25:48 2001]
35 *---------------------------------------------------------------------------*/
37 #include "isdnd.h"
39 /* table of state descriptions */
41 static char *state_text[N_STATES] = {
42 "idle",
43 "dialing",
44 "waitdialretry",
45 "dialretry",
47 "pcb-dialing",
48 "pcb-dialfail",
49 "pcb-waitcall",
51 "acb-waitdisc",
52 "acb-waitdial",
53 "acb-dialing",
54 "acb-dialfail",
56 "accepted",
57 "connected",
58 "waitdisconnect",
59 "down",
60 "alert",
62 "Illegal State"
65 /* table of event descriptions */
67 static char *event_text[N_EVENTS] = {
69 /* incoming messages */
71 "msg-con-ind",
72 "msg-con-act-ind",
73 "msg-disc-ind",
74 "msg-dialout",
76 /* local events */
78 "timeout",
79 "disconnect-req",
80 "callback-req",
81 "alert-req",
83 /* illegal */
85 "Illegal Event"
88 /*---------------------------------------------------------------------------*
89 * illegal state default action
90 *---------------------------------------------------------------------------*/
91 static void
92 F_ill(cfg_entry_t *cep)
94 DBGL(DL_STATE, (log(LL_DBG, "F_ill: Illegal State reached !!!")));
97 /*---------------------------------------------------------------------------*
98 * No change, No action
99 *---------------------------------------------------------------------------*/
100 static void
101 F_NcNa(cfg_entry_t *cep)
105 /*---------------------------------------------------------------------------*
106 * incoming CONNECT, accepting call
107 *---------------------------------------------------------------------------*/
108 static void
109 F_MCI(cfg_entry_t *cep)
111 DBGL(DL_STATE, (log(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 *---------------------------------------------------------------------------*/
119 static void
120 F_MCAI(cfg_entry_t *cep)
122 DBGL(DL_STATE, (log(LL_DBG, "F_MCAI: Connection active!")));
124 stop_timer(cep);
126 if((cep->dialin_reaction == REACT_ANSWER) &&
127 (cep->b1protocol == BPROT_NONE))
129 exec_answer(cep);
133 /*---------------------------------------------------------------------------*
134 * timeout
135 *---------------------------------------------------------------------------*/
136 static void
137 F_TIMO(cfg_entry_t *cep)
139 DBGL(DL_STATE, (log(LL_DBG, "F_TIMO: Timout occured!")));
140 sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
141 cep->cdid = CDID_UNUSED;
144 /*---------------------------------------------------------------------------*
145 * incoming disconnect indication
146 *---------------------------------------------------------------------------*/
147 static void
148 F_IDIS(cfg_entry_t *cep)
150 DBGL(DL_STATE, (log(LL_DBG, "F_IDIS: disconnect indication")));
151 cep->cdid = CDID_UNUSED;
154 /*---------------------------------------------------------------------------*
155 * local disconnect request
156 *---------------------------------------------------------------------------*/
157 static void
158 F_DRQ(cfg_entry_t *cep)
160 DBGL(DL_STATE, (log(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 *---------------------------------------------------------------------------*/
167 static void
168 F_MDI(cfg_entry_t *cep)
170 DBGL(DL_STATE, (log(LL_DBG, "F_MDI: disconnect indication, local disconnected")));
171 cep->cdid = CDID_UNUSED;
174 /*---------------------------------------------------------------------------*
175 * local requested outgoing dial
176 *---------------------------------------------------------------------------*/
177 static void
178 F_DIAL(cfg_entry_t *cep)
180 DBGL(DL_STATE, (log(LL_DBG, "F_DIAL: local dial out request")));
182 if(cep->dialrandincr)
183 cep->randomtime = (random() & RANDOM_MASK) + cep->recoverytime;
185 cep->dial_count = 0;
187 select_first_dialno(cep);
189 sendm_connect_req(cep);
192 /*---------------------------------------------------------------------------*
193 * outgoing dial successfull
194 *---------------------------------------------------------------------------*/
195 static void
196 F_DOK(cfg_entry_t *cep)
198 DBGL(DL_STATE, (log(LL_DBG, "F_DOK: dial out ok")));
199 select_this_dialno(cep);
202 /*---------------------------------------------------------------------------*
203 * outgoing dial fail (ST_SUSE !!!)
204 *---------------------------------------------------------------------------*/
205 static void
206 F_DFL(cfg_entry_t *cep)
208 cep->last_release_time = time(NULL);
210 if(cep->dialouttype == DIALOUT_NORMAL)
212 cep->dial_count++;
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, (log(LL_DBG, "F_DFL: dial fail, dial retry")));
219 select_next_dialno(cep);
220 cep->cdid = CDID_RESERVED;
221 cep->state = ST_DIALRTMRCHD;
222 return;
225 /* retries exhausted */
227 if(!cep->usedown)
229 DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial retry fail, dial retries exhausted")));
230 dialresponse(cep, DSTAT_TFAIL);
231 cep->cdid = CDID_UNUSED;
232 cep->dial_count = 0;
233 cep->state = ST_IDLE;
234 return;
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, (log(LL_DBG, "F_DFL: dial retry cycle fail, setting interface down!")));
245 dialresponse(cep, DSTAT_PFAIL);
246 if_down(cep);
247 cep->state = ST_DOWN;
249 else
251 /* enter new dial retry cycle */
252 DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial retry cycle fail, enter new retry cycle!")));
253 select_next_dialno(cep);
254 cep->state = ST_DIALRTMRCHD;
257 cep->dial_count = 0;
258 cep->cdid = CDID_RESERVED;
260 else /* cdp->dialouttype == DIALOUT_CALLEDBACK */
262 DBGL(DL_STATE, (log(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 *---------------------------------------------------------------------------*/
271 static void
272 F_ACBW(cfg_entry_t *cep)
274 DBGL(DL_STATE, (log(LL_DBG, "F_ACBW: local callback, wait callback recovery time")));
276 if(cep->dialrandincr)
277 cep->randomtime = (random() & RANDOM_MASK) + cep->recoverytime;
279 cep->dial_count = 0;
281 cep->cdid = CDID_RESERVED;
284 /*---------------------------------------------------------------------------*
285 * active callback dialout retry (ST_SUSE !!!)
286 *---------------------------------------------------------------------------*/
287 static void
288 F_ACBR(cfg_entry_t *cep)
290 cep->dial_count++;
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, (log(LL_DBG, "F_ACBR: dial fail, dial retry")));
297 select_next_dialno(cep);
298 cep->cdid = CDID_RESERVED;
299 cep->state = ST_ACB_DIALFAIL;
300 return;
303 /* retries exhausted */
305 if(!cep->usedown)
307 DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial retry fail, dial retries exhausted")));
308 dialresponse(cep, DSTAT_TFAIL);
309 cep->cdid = CDID_UNUSED;
310 cep->dial_count = 0;
311 cep->state = ST_IDLE;
312 return;
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, (log(LL_DBG, "F_ACBR: dial retry cycle fail, setting interface down!")));
323 dialresponse(cep, DSTAT_PFAIL);
324 if_down(cep);
325 cep->state = ST_DOWN;
327 else
329 /* enter new dial retry cycle */
330 DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial retry cycle fail, enter new retry cycle!")));
331 select_next_dialno(cep);
332 cep->state = ST_ACB_DIALFAIL;
335 cep->dial_count = 0;
336 cep->cdid = CDID_RESERVED;
339 /*---------------------------------------------------------------------------*
340 * local requested to send ALERT message
341 *---------------------------------------------------------------------------*/
342 static void
343 F_ALRT(cfg_entry_t *cep)
345 DBGL(DL_STATE, (log(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 *---------------------------------------------------------------------------*/
355 struct state_tab {
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 /* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
362 /* messages */
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}},
368 /* local requests */
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}},
374 /* illegal */
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 /*---------------------------------------------------------------------------*
380 * event handler
381 *---------------------------------------------------------------------------*/
382 void
383 next_state(cfg_entry_t *cep, int event)
385 int currstate, newstate;
387 if(event > N_EVENTS)
389 log(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 log(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 log(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, (log(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 log(LL_ERR, "FSM ILLEGAL STATE, event=%s: oldstate=%s => newstate=%s]",
421 event_text[event],
422 state_text[currstate],
423 state_text[newstate]);
426 if(newstate == ST_SUSE)
428 DBGL(DL_STATE, (log(LL_DBG, "FSM (SUSE) event [%s]: [%s => %s]", event_text[event],
429 state_text[currstate],
430 state_text[cep->state])));
432 else
434 cep->state = newstate;
438 /*---------------------------------------------------------------------------*
439 * return pointer to current state description
440 *---------------------------------------------------------------------------*/
441 char *
442 printstate(cfg_entry_t *cep)
444 return((char *) state_text[cep->state]);
447 /* EOF */