No empty .Rs/.Re
[netbsd-mini2440.git] / usr.sbin / isdn / isdnd / rc_config.c
blob7e7e1690da1ceab4f27480d75a4e98444588a241
1 /*
2 * Copyright (c) 1997, 2000 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 * i4b daemon - config file processing
28 * -----------------------------------
30 * $Id: rc_config.c,v 1.25 2009/04/16 05:56:32 lukem Exp $
32 * $FreeBSD$
34 * last edit-date: [Sat Jan 6 12:57:36 2001]
36 *---------------------------------------------------------------------------*/
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
43 #include <sys/callout.h>
44 #include <sys/ioctl.h>
45 #include <ifaddrs.h>
47 #include "isdnd.h"
48 #include "rc_parse.h"
50 #include "monitor.h"
52 extern int lineno;
53 extern char *yytext;
55 extern FILE *yyin;
56 extern int yyparse(void);
58 static void set_config_defaults(void);
59 static void check_config(void);
60 static void print_config(void);
61 static void parse_valid(char *dt);
62 static int lookup_l4_driver(const char *name);
63 void init_currrent_cfg_state(void);
64 static void set_isppp_auth(struct cfg_entry*);
65 static void set_autoupdown(struct cfg_entry*);
66 void flush_config(void);
68 static int nregexpr = 0;
69 static int nregprog = 0;
70 static struct cfg_entry * current_cfe = NULL;
71 struct isdn_ctrl_state * cur_ctrl = NULL;
73 /*---------------------------------------------------------------------------*
74 * called from main to read and process config file
75 *---------------------------------------------------------------------------*/
76 void
77 configure(const char *filename, int reread)
79 extern void reset_scanner(FILE *inputfile);
81 set_config_defaults();
83 yyin = fopen(filename, "r");
85 if (reread)
87 reset_scanner(yyin);
88 current_cfe = NULL;
91 if (yyin == NULL)
93 logit(LL_ERR, "cannot fopen file [%s]", filename);
94 exit(1);
97 yyparse();
99 monitor_fixup_rights();
101 check_config(); /* validation and consistency check */
103 fclose(yyin);
105 if (do_print)
107 if (config_error_flag)
109 logit(LL_ERR, "there were %d error(s) in the configuration file, terminating!", config_error_flag);
110 exit(1);
112 print_config();
113 do_exit(0);
117 /*---------------------------------------------------------------------------*
118 * yacc error routine
119 *---------------------------------------------------------------------------*/
120 void
121 yyerror(const char *msg)
123 logit(LL_ERR, "configuration error: %s at line %d, token \"%s\"", msg, lineno+1, yytext);
124 config_error_flag++;
128 * Prepare a new default entry
130 void
131 init_currrent_cfg_state()
133 if (current_cfe != NULL) {
134 add_cfg_entry(current_cfe);
136 current_cfe = malloc(sizeof(struct cfg_entry));
137 memset(current_cfe, 0, sizeof(struct cfg_entry));
139 current_cfe->isdncontroller = INVALID;
140 current_cfe->isdnchannel = CHAN_ANY;
141 current_cfe->usrdevice = INVALID;
142 current_cfe->usrdeviceunit = INVALID;
143 current_cfe->remote_numbers_handling = RNH_LAST;
144 current_cfe->dialin_reaction = REACT_IGNORE;
145 current_cfe->b1protocol = BPROT_NONE;
146 current_cfe->unitlength = UNITLENGTH_DEFAULT;
147 current_cfe->earlyhangup = EARLYHANGUP_DEFAULT;
148 current_cfe->ratetype = INVALID_RATE;
149 current_cfe->unitlengthsrc = ULSRC_NONE;
150 current_cfe->answerprog = ANSWERPROG_DEF;
151 current_cfe->callbackwait = CALLBACKWAIT_MIN;
152 current_cfe->calledbackwait = CALLEDBACKWAIT_MIN;
153 current_cfe->dialretries = DIALRETRIES_DEF;
154 current_cfe->recoverytime = RECOVERYTIME_MIN;
155 current_cfe->dialouttype = DIALOUT_NORMAL;
156 current_cfe->inout = DIR_INOUT;
157 current_cfe->ppp_expect_auth = AUTH_UNDEF;
158 current_cfe->ppp_send_auth = AUTH_UNDEF;
159 current_cfe->ppp_auth_flags = AUTH_RECHALLENGE | AUTH_REQUIRED;
160 current_cfe->cdid = CDID_UNUSED;
161 current_cfe->state = ST_IDLE;
162 current_cfe->aoc_valid = AOC_INVALID;
163 current_cfe->autoupdown = AUTOUPDOWN_YES;
166 /*---------------------------------------------------------------------------*
167 * fill all config entries with default values
168 *---------------------------------------------------------------------------*/
169 static void
170 set_config_defaults(void)
172 int i;
174 /* system section cleanup */
176 nregprog = nregexpr = 0;
178 rt_prio = RTPRIO_NOTUSED;
180 mailer[0] = '\0';
181 mailto[0] = '\0';
183 /* clean regular expression table */
185 for (i=0; i < MAX_RE; i++)
187 if (rarr[i].re_expr)
188 free(rarr[i].re_expr);
189 rarr[i].re_expr = NULL;
191 if (rarr[i].re_prog)
192 free(rarr[i].re_prog);
193 rarr[i].re_prog = NULL;
195 rarr[i].re_flg = 0;
198 strlcpy(rotatesuffix, "", sizeof(rotatesuffix));
201 static void
202 set_autoupdown(struct cfg_entry *cep)
204 struct ifaddrs *res = NULL, *p;
205 struct ifreq ifr;
206 int r, s, cnt, in6;
208 s = socket(AF_INET, SOCK_DGRAM, 0);
209 memset(&ifr, 0, sizeof ifr);
210 snprintf(ifr.ifr_name, sizeof ifr.ifr_name, "%s%d", cep->usrdevicename, cep->usrdeviceunit);
211 r = ioctl(s, SIOCGIFFLAGS, &ifr);
214 * See if this interface has got any valid addresses - if not,
215 * leave it alone.
217 if (r >= 0 && !(ifr.ifr_flags & IFF_UP)) {
218 cnt = in6 = 0;
219 if (getifaddrs(&res) == 0) {
220 for (p = res; p; p = p->ifa_next) {
221 if (p->ifa_addr == NULL)
222 continue;
223 if (p->ifa_addr->sa_family == AF_LINK)
224 continue;
225 if (strcmp(p->ifa_name, ifr.ifr_name) != 0)
226 continue;
227 if (p->ifa_addr->sa_family == AF_INET6)
228 in6 = 1;
229 cnt++;
231 freeifaddrs(res);
234 if (in6)
235 cnt--; /* XXX - heuristic to adjust for INET6 local scope */
237 /* Ok, we have some addres - so UP the interface */
238 if (cnt > 0) {
239 ifr.ifr_flags |= IFF_UP;
240 r = ioctl(s, SIOCSIFFLAGS, &ifr);
241 if (r >= 0)
242 cep->autoupdown |= AUTOUPDOWN_DONE;
246 close(s);
249 static void
250 set_isppp_auth(struct cfg_entry *cep)
252 struct spppauthcfg spcfg;
253 int s;
254 int doioctl = 0;
256 if (cep->ppp_expect_auth == AUTH_UNDEF
257 && cep->ppp_send_auth == AUTH_UNDEF)
258 return;
260 if (cep->ppp_expect_auth == AUTH_NONE
261 || cep->ppp_send_auth == AUTH_NONE)
262 doioctl = 1;
264 if ((cep->ppp_expect_auth == AUTH_CHAP
265 || cep->ppp_expect_auth == AUTH_PAP)
266 && cep->ppp_expect_name != NULL
267 && cep->ppp_expect_password != NULL)
268 doioctl = 1;
270 if ((cep->ppp_send_auth == AUTH_CHAP || cep->ppp_send_auth == AUTH_PAP)
271 && cep->ppp_send_name != NULL
272 && cep->ppp_send_password != NULL)
273 doioctl = 1;
275 if (!doioctl)
276 return;
278 memset(&spcfg, 0, sizeof spcfg);
279 snprintf(spcfg.ifname, sizeof(spcfg.ifname), "%s%d",
280 cep->usrdevicename, cep->usrdeviceunit);
282 /* use a random AF to create the socket */
283 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
284 logit(LL_ERR, "ERROR opening control socket at line %d!", lineno);
285 config_error_flag++;
286 return;
289 if (ioctl(s, SPPPGETAUTHCFG, &spcfg) == -1) {
290 logit(LL_ERR, "ERROR fetching active PPP authentication info for %s at line %d!", spcfg.ifname, lineno);
291 close(s);
292 config_error_flag++;
293 return;
295 if (cep->ppp_expect_auth != AUTH_UNDEF)
297 if (cep->ppp_expect_auth == AUTH_NONE)
299 spcfg.hisauth = SPPP_AUTHPROTO_NONE;
301 else if ((cep->ppp_expect_auth == AUTH_CHAP
302 || cep->ppp_expect_auth == AUTH_PAP)
303 && cep->ppp_expect_name != NULL
304 && cep->ppp_expect_password != NULL)
306 spcfg.hisauth = cep->ppp_expect_auth == AUTH_PAP ? SPPP_AUTHPROTO_PAP : SPPP_AUTHPROTO_CHAP;
307 spcfg.hisname = cep->ppp_expect_name;
308 spcfg.hisname_length = strlen(cep->ppp_expect_name)+1;
309 spcfg.hissecret = cep->ppp_expect_password;
310 spcfg.hissecret_length = strlen(cep->ppp_expect_password)+1;
313 if (cep->ppp_send_auth != AUTH_UNDEF)
315 if (cep->ppp_send_auth == AUTH_NONE)
317 spcfg.myauth = SPPP_AUTHPROTO_NONE;
319 else if ((cep->ppp_send_auth == AUTH_CHAP
320 || cep->ppp_send_auth == AUTH_PAP)
321 && cep->ppp_send_name != NULL
322 && cep->ppp_send_password != NULL)
324 spcfg.myauth = cep->ppp_send_auth == AUTH_PAP ? SPPP_AUTHPROTO_PAP : SPPP_AUTHPROTO_CHAP;
325 spcfg.myname = cep->ppp_send_name;
326 spcfg.myname_length = strlen(cep->ppp_send_name)+1;
327 spcfg.mysecret = cep->ppp_send_password;
328 spcfg.mysecret_length = strlen(cep->ppp_send_password)+1;
330 if (cep->ppp_auth_flags & AUTH_REQUIRED)
331 spcfg.hisauthflags &= ~SPPP_AUTHFLAG_NOCALLOUT;
332 else
333 spcfg.hisauthflags |= SPPP_AUTHFLAG_NOCALLOUT;
335 if (cep->ppp_auth_flags & AUTH_RECHALLENGE)
336 spcfg.hisauthflags &= ~SPPP_AUTHFLAG_NORECHALLENGE;
337 else
338 spcfg.hisauthflags |= SPPP_AUTHFLAG_NORECHALLENGE;
342 if (ioctl(s, SPPPSETAUTHCFG, &spcfg) == -1) {
343 logit(LL_ERR, "ERROR setting new PPP authentication parameters for %s at line %d!", spcfg.ifname, lineno);
344 config_error_flag++;
346 close(s);
349 /*---------------------------------------------------------------------------*
350 * extract values from config and fill table
351 *---------------------------------------------------------------------------*/
352 void
353 cfg_setval(int keyword)
355 int i;
357 switch (keyword)
359 case ACCTALL:
360 acct_all = yylval.booln;
361 DBGL(DL_RCCF, (logit(LL_DBG, "system: acctall = %d", yylval.booln)));
362 break;
364 case ACCTFILE:
365 strlcpy(acctfile, yylval.str, sizeof(acctfile));
366 DBGL(DL_RCCF, (logit(LL_DBG, "system: acctfile = %s", yylval.str)));
367 break;
369 case ALERT:
370 if (yylval.num < MINALERT)
372 yylval.num = MINALERT;
373 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: alert < %d, min = %d", current_cfe->name, MINALERT, yylval.num)));
375 else if (yylval.num > MAXALERT)
377 yylval.num = MAXALERT;
378 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: alert > %d, min = %d", current_cfe->name, MAXALERT, yylval.num)));
381 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: alert = %d", current_cfe->name, yylval.num)));
382 current_cfe->alert = yylval.num;
383 break;
385 case ALIASING:
386 DBGL(DL_RCCF, (logit(LL_DBG, "system: aliasing = %d", yylval.booln)));
387 aliasing = yylval.booln;
388 break;
390 case ALIASFNAME:
391 strlcpy(aliasfile, yylval.str, sizeof(aliasfile));
392 DBGL(DL_RCCF, (logit(LL_DBG, "system: aliasfile = %s", yylval.str)));
393 break;
395 case ANSWERPROG:
396 if ((current_cfe->answerprog = strdup(yylval.str)) == NULL)
398 logit(LL_ERR, "entry %s: answerstring, malloc failed!", current_cfe->name);
399 do_exit(1);
401 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: answerprog = %s", current_cfe->name, yylval.str)));
402 break;
404 case B1PROTOCOL:
405 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: b1protocol = %s", current_cfe->name, yylval.str)));
406 if (!(strcmp(yylval.str, "raw")))
407 current_cfe->b1protocol = BPROT_NONE;
408 else if (!(strcmp(yylval.str, "hdlc")))
409 current_cfe->b1protocol = BPROT_RHDLC;
410 else
412 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"b1protocol\" at line %d!", lineno);
413 config_error_flag++;
415 break;
417 case BEEPCONNECT:
418 do_bell = yylval.booln;
419 DBGL(DL_RCCF, (logit(LL_DBG, "system: beepconnect = %d", yylval.booln)));
420 break;
422 case BUDGETCALLBACKPERIOD:
423 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-callbackperiod = %d", current_cfe->name, yylval.num)));
424 current_cfe->budget_callbackperiod = yylval.num;
425 break;
427 case BUDGETCALLBACKNCALLS:
428 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-callbackncalls = %d", current_cfe->name, yylval.num)));
429 current_cfe->budget_callbackncalls = yylval.num;
430 break;
432 case BUDGETCALLOUTPERIOD:
433 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-calloutperiod = %d", current_cfe->name, yylval.num)));
434 current_cfe->budget_calloutperiod = yylval.num;
435 break;
437 case BUDGETCALLOUTNCALLS:
438 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-calloutncalls = %d", current_cfe->name, yylval.num)));
439 current_cfe->budget_calloutncalls = yylval.num;
440 break;
442 case AUTOUPDOWN:
443 current_cfe->autoupdown = yylval.booln;
444 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: autoupdown = %d", current_cfe->name, yylval.booln)));
445 break;
447 case BUDGETCALLBACKSFILEROTATE:
448 current_cfe->budget_callbacksfile_rotate = yylval.booln;
449 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-callbacksfile-rotate = %d", current_cfe->name, yylval.booln)));
450 break;
452 case BUDGETCALLBACKSFILE:
454 FILE *fp;
455 int s, l;
456 int n;
457 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-callbacksfile = %s", yylval.str)));
458 fp = fopen(yylval.str, "r");
459 if (fp != NULL)
461 if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) != 3)
463 DBGL(DL_RCCF, (logit(LL_DBG, "entry %d: initializing budget-callbacksfile %s", current_cfe->name, yylval.str)));
464 fclose(fp);
465 fp = fopen(yylval.str, "w");
466 if (fp != NULL) {
467 fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
468 fclose(fp);
470 } else
471 fclose(fp);
473 else
475 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: creating budget-callbacksfile %s", current_cfe->name, yylval.str)));
476 fp = fopen(yylval.str, "w");
477 if (fp != NULL)
478 fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
479 fclose(fp);
482 fp = fopen(yylval.str, "r");
483 if (fp != NULL)
485 if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) == 3)
487 if ((current_cfe->budget_callbacks_file = strdup(yylval.str)) == NULL)
489 logit(LL_ERR, "entry %s: budget-callbacksfile, malloc failed!", current_cfe->name);
490 do_exit(1);
492 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: using callbacksfile %s", current_cfe->name, yylval.str)));
494 fclose(fp);
497 break;
499 case BUDGETCALLOUTSFILEROTATE:
500 current_cfe->budget_calloutsfile_rotate = yylval.booln;
501 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-calloutsfile-rotate = %d", current_cfe->name, yylval.booln)));
502 break;
504 case BUDGETCALLOUTSFILE:
506 FILE *fp;
507 int s, l;
508 int n;
509 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: budget-calloutsfile = %s", current_cfe->name, yylval.str)));
510 fp = fopen(yylval.str, "r");
511 if (fp != NULL)
513 if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) != 3)
515 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: initializing budget-calloutsfile %s", current_cfe->name, yylval.str)));
516 fclose(fp);
517 fp = fopen(yylval.str, "w");
518 if (fp != NULL)
519 fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
520 fclose(fp);
523 else
525 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: creating budget-calloutsfile %s", current_cfe->name, yylval.str)));
526 fp = fopen(yylval.str, "w");
527 if (fp != NULL)
528 fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
529 fclose(fp);
532 fp = fopen(yylval.str, "r");
533 if (fp != NULL)
535 if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) == 3)
537 if ((current_cfe->budget_callouts_file = strdup(yylval.str)) == NULL)
539 logit(LL_ERR, "entry %s: budget-calloutsfile, malloc failed!", current_cfe->name);
540 do_exit(1);
542 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: using calloutsfile %s", current_cfe->name, yylval.str)));
544 fclose(fp);
547 break;
549 case CALLBACKWAIT:
550 if (yylval.num < CALLBACKWAIT_MIN)
552 yylval.num = CALLBACKWAIT_MIN;
553 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: callbackwait < %d, min = %d", current_cfe->name, CALLBACKWAIT_MIN, yylval.num)));
556 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: callbackwait = %d", current_cfe->name, yylval.num)));
557 current_cfe->callbackwait = yylval.num;
558 break;
560 case CALLEDBACKWAIT:
561 if (yylval.num < CALLEDBACKWAIT_MIN)
563 yylval.num = CALLEDBACKWAIT_MIN;
564 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: calledbackwait < %d, min = %d", current_cfe->name, CALLEDBACKWAIT_MIN, yylval.num)));
567 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: calledbackwait = %d", current_cfe->name, yylval.num)));
568 current_cfe->calledbackwait = yylval.num;
569 break;
571 case CONNECTPROG:
572 if ((current_cfe->connectprog = strdup(yylval.str)) == NULL)
574 logit(LL_ERR, "entry %s: connectprog, malloc failed!", current_cfe->name);
575 do_exit(1);
577 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: connectprog = %s", current_cfe->name, yylval.str)));
578 break;
580 case DIALOUTTYPE:
581 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: dialouttype = %s", current_cfe->name, yylval.str)));
582 if (!(strcmp(yylval.str, "normal")))
583 current_cfe->dialouttype = DIALOUT_NORMAL;
584 else if (!(strcmp(yylval.str, "calledback")))
585 current_cfe->dialouttype = DIALOUT_CALLEDBACK;
586 else
588 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"dialout-type\" at line %d!", lineno);
589 config_error_flag++;
591 break;
593 case DIALRETRIES:
594 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: dialretries = %d", current_cfe->name, yylval.num)));
595 current_cfe->dialretries = yylval.num;
596 break;
598 case DIALRANDINCR:
599 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: dialrandincr = %d", current_cfe->name, yylval.booln)));
600 current_cfe->dialrandincr = yylval.booln;
601 break;
603 case DIRECTION:
604 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: direction = %s", current_cfe->name, yylval.str)));
606 if (!(strcmp(yylval.str, "inout")))
607 current_cfe->inout = DIR_INOUT;
608 else if (!(strcmp(yylval.str, "in")))
609 current_cfe->inout = DIR_INONLY;
610 else if (!(strcmp(yylval.str, "out")))
611 current_cfe->inout = DIR_OUTONLY;
612 else
614 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"direction\" at line %d!", lineno);
615 config_error_flag++;
617 break;
619 case DISCONNECTPROG:
620 if ((current_cfe->disconnectprog = strdup(yylval.str)) == NULL)
622 logit(LL_ERR, "entry %s: disconnectprog, malloc failed!", current_cfe->name);
623 do_exit(1);
625 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: disconnectprog = %s", current_cfe->name, yylval.str)));
626 break;
628 case DOWNTRIES:
629 if (yylval.num > DOWN_TRIES_MAX)
630 yylval.num = DOWN_TRIES_MAX;
631 else if (yylval.num < DOWN_TRIES_MIN)
632 yylval.num = DOWN_TRIES_MIN;
634 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: downtries = %d", current_cfe->name, yylval.num)));
635 current_cfe->downtries = yylval.num;
636 break;
638 case DOWNTIME:
639 if (yylval.num > DOWN_TIME_MAX)
640 yylval.num = DOWN_TIME_MAX;
641 else if (yylval.num < DOWN_TIME_MIN)
642 yylval.num = DOWN_TIME_MIN;
644 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: downtime = %d", current_cfe->name, yylval.num)));
645 current_cfe->downtime = yylval.num;
646 break;
648 case EARLYHANGUP:
649 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: earlyhangup = %d", current_cfe->name, yylval.num)));
650 current_cfe->earlyhangup = yylval.num;
651 break;
653 case EXTCALLATTR:
654 DBGL(DL_RCCF, (logit(LL_DBG, "system: extcallattr = %d", yylval.booln)));
655 extcallattr = yylval.booln;
656 break;
658 case FIRMWARE:
659 DBGL(DL_RCCF, (logit(LL_DBG, "controller %d: firmware = %s", cur_ctrl->isdnif, yylval.str)));
660 cur_ctrl->firmware = strdup(yylval.str);
661 break;
663 case HOLIDAYFILE:
664 strlcpy(holidayfile, yylval.str, sizeof(holidayfile));
665 DBGL(DL_RCCF, (logit(LL_DBG, "system: holidayfile = %s", yylval.str)));
666 break;
668 case IDLE_ALG_OUT:
669 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: idle-algorithm-outgoing = %s", current_cfe->name, yylval.str)));
671 if (!(strcmp(yylval.str, "fix-unit-size")))
673 current_cfe->shorthold_algorithm = SHA_FIXU;
675 else if (!(strcmp(yylval.str, "var-unit-size")))
677 current_cfe->shorthold_algorithm = SHA_VARU;
679 else
681 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"idle-algorithm-outgoing\" at line %d!", lineno);
682 config_error_flag++;
684 break;
686 case IDLETIME_IN:
687 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: idle_time_in = %d", current_cfe->name, yylval.num)));
688 current_cfe->idle_time_in = yylval.num;
689 break;
691 case IDLETIME_OUT:
692 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: idle_time_out = %d", current_cfe->name, yylval.num)));
693 current_cfe->idle_time_out = yylval.num;
694 break;
696 case ISDNCONTROLLER:
697 current_cfe->isdncontroller = yylval.num;
698 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: isdncontroller = %d", current_cfe->name, yylval.num)));
699 break;
701 case ISDNCHANNEL:
702 if (yylval.num == 0 || yylval.num == -1) {
703 current_cfe->isdnchannel = CHAN_ANY;
704 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: isdnchannel = any", current_cfe->name)));
705 } else if (yylval.num > MAX_BCHAN) {
706 logit(LL_DBG, "entry %s: isdnchannel value out of range", current_cfe->name);
707 config_error_flag++;
708 } else {
709 current_cfe->isdnchannel = yylval.num - 1;
710 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: isdnchannel = %d", current_cfe->name, yylval.num)));
712 break;
714 case ISDNTIME:
715 DBGL(DL_RCCF, (logit(LL_DBG, "system: isdntime = %d", yylval.booln)));
716 isdntime = yylval.booln;
717 break;
719 case ISDNTXDELIN:
720 current_cfe->isdntxdelin = yylval.num;
721 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: isdntxdel-incoming = %d", current_cfe->name, yylval.num)));
722 break;
724 case ISDNTXDELOUT:
725 current_cfe->isdntxdelout = yylval.num;
726 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: isdntxdel-outgoing = %d", current_cfe->name, yylval.num)));
727 break;
729 case LOCAL_PHONE_DIALOUT:
730 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: local_phone_dialout = %s", current_cfe->name, yylval.str)));
731 strlcpy(current_cfe->local_phone_dialout, yylval.str,
732 sizeof(current_cfe->local_phone_dialout));
733 break;
735 case LOCAL_PHONE_INCOMING:
736 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: local_phone_incoming = %s", current_cfe->name, yylval.str)));
737 strlcpy(current_cfe->local_phone_incoming, yylval.str,
738 sizeof(current_cfe->local_phone_incoming));
739 break;
741 case MAILER:
742 strlcpy(mailer, yylval.str, sizeof(mailer));
743 DBGL(DL_RCCF, (logit(LL_DBG, "system: mailer = %s", yylval.str)));
744 break;
746 case MAILTO:
747 strlcpy(mailto, yylval.str, sizeof(mailto));
748 DBGL(DL_RCCF, (logit(LL_DBG, "system: mailto = %s", yylval.str)));
749 break;
751 case MONITORPORT:
752 monitorport = yylval.num;
753 DBGL(DL_RCCF, (logit(LL_DBG, "system: monitorport = %d", yylval.num)));
754 break;
756 case MONITORSW:
757 if (yylval.booln && inhibit_monitor)
759 do_monitor = 0;
760 DBGL(DL_RCCF, (logit(LL_DBG, "system: monitor-enable overriden by command line flag")));
762 else
764 do_monitor = yylval.booln;
765 DBGL(DL_RCCF, (logit(LL_DBG, "system: monitor-enable = %d", yylval.booln)));
767 break;
769 case NAME:
770 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: name = %s", current_cfe->name, yylval.str)));
771 strlcpy(current_cfe->name, yylval.str,
772 sizeof(current_cfe->name));
773 break;
775 case PPP_AUTH_RECHALLENGE:
776 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-auth-rechallenge = %d", current_cfe->name, yylval.booln)));
777 if (yylval.booln)
778 current_cfe->ppp_auth_flags |= AUTH_RECHALLENGE;
779 else
780 current_cfe->ppp_auth_flags &= ~AUTH_RECHALLENGE;
781 break;
783 case PPP_AUTH_PARANOID:
784 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-auth-paranoid = %d", current_cfe->name, yylval.booln)));
785 if (yylval.booln)
786 current_cfe->ppp_auth_flags |= AUTH_REQUIRED;
787 else
788 current_cfe->ppp_auth_flags &= ~AUTH_REQUIRED;
789 break;
791 case PPP_EXPECT_AUTH:
792 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-expect-auth = %s", current_cfe->name, yylval.str)));
793 if (!(strcmp(yylval.str, "none")))
794 current_cfe->ppp_expect_auth = AUTH_NONE;
795 else if (!(strcmp(yylval.str, "pap")))
796 current_cfe->ppp_expect_auth = AUTH_PAP;
797 else if (!(strcmp(yylval.str, "chap")))
798 current_cfe->ppp_expect_auth = AUTH_CHAP;
799 else
801 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"ppp-expect-auth\" at line %d!", lineno);
802 config_error_flag++;
803 break;
805 break;
807 case PPP_EXPECT_NAME:
808 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-expect-name = %s", current_cfe->name, yylval.str)));
809 if (current_cfe->ppp_expect_name)
810 free(current_cfe->ppp_expect_name);
811 current_cfe->ppp_expect_name = strdup(yylval.str);
812 break;
814 case PPP_EXPECT_PASSWORD:
815 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-expect-password = %s", current_cfe->name, yylval.str)));
816 if (current_cfe->ppp_expect_password)
817 free(current_cfe->ppp_expect_password);
818 current_cfe->ppp_expect_password = strdup(yylval.str);
819 break;
821 case PPP_SEND_AUTH:
822 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-send-auth = %s", current_cfe->name, yylval.str)));
823 if (!(strcmp(yylval.str, "none")))
824 current_cfe->ppp_send_auth = AUTH_NONE;
825 else if (!(strcmp(yylval.str, "pap")))
826 current_cfe->ppp_send_auth = AUTH_PAP;
827 else if (!(strcmp(yylval.str, "chap")))
828 current_cfe->ppp_send_auth = AUTH_CHAP;
829 else
831 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"ppp-send-auth\" at line %d!", lineno);
832 config_error_flag++;
833 break;
835 break;
837 case PPP_SEND_NAME:
838 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-send-name = %s", current_cfe->name, yylval.str)));
839 if (current_cfe->ppp_send_name)
840 free(current_cfe->ppp_send_name);
841 current_cfe->ppp_send_name = strdup(yylval.str);
842 break;
844 case PPP_SEND_PASSWORD:
845 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ppp-send-password = %s", current_cfe->name, yylval.str)));
846 if (current_cfe->ppp_send_password)
847 free(current_cfe->ppp_send_password);
848 current_cfe->ppp_send_password = strdup(yylval.str);
849 break;
851 case PROTOCOL:
852 DBGL(DL_RCCF, (logit(LL_DBG, "controller %d: protocol = %s", cur_ctrl->isdnif, yylval.str)));
853 if (!(strcmp(yylval.str, "dss1")))
854 cur_ctrl->protocol = PROTOCOL_DSS1;
855 else if (!(strcmp(yylval.str, "d64s")))
856 cur_ctrl->protocol = PROTOCOL_D64S;
857 else
859 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"protocol\" at line %d!", lineno);
860 config_error_flag++;
862 break;
864 case REACTION:
865 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: dialin_reaction = %s", current_cfe->name, yylval.str)));
866 if (!(strcmp(yylval.str, "accept")))
867 current_cfe->dialin_reaction = REACT_ACCEPT;
868 else if (!(strcmp(yylval.str, "reject")))
869 current_cfe->dialin_reaction = REACT_REJECT;
870 else if (!(strcmp(yylval.str, "ignore")))
871 current_cfe->dialin_reaction = REACT_IGNORE;
872 else if (!(strcmp(yylval.str, "answer")))
873 current_cfe->dialin_reaction = REACT_ANSWER;
874 else if (!(strcmp(yylval.str, "callback")))
875 current_cfe->dialin_reaction = REACT_CALLBACK;
876 else
878 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"dialin_reaction\" at line %d!", lineno);
879 config_error_flag++;
881 break;
883 case REMOTE_PHONE_DIALOUT:
884 if (current_cfe->remote_numbers_count >= MAXRNUMBERS)
886 logit(LL_ERR, "ERROR parsing config file: too many remote numbers at line %d!", lineno);
887 config_error_flag++;
888 break;
891 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: remote_phone_dialout #%d = %s",
892 current_cfe->name, current_cfe->remote_numbers_count, yylval.str)));
894 strlcpy(current_cfe->remote_numbers[current_cfe->remote_numbers_count].number,
895 yylval.str,
896 sizeof(current_cfe->remote_numbers[current_cfe->remote_numbers_count].number));
897 current_cfe->remote_numbers[current_cfe->remote_numbers_count].flag = 0;
899 current_cfe->remote_numbers_count++;
901 break;
903 case REMOTE_NUMBERS_HANDLING:
904 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: remdial_handling = %s", current_cfe->name, yylval.str)));
905 if (!(strcmp(yylval.str, "next")))
906 current_cfe->remote_numbers_handling = RNH_NEXT;
907 else if (!(strcmp(yylval.str, "last")))
908 current_cfe->remote_numbers_handling = RNH_LAST;
909 else if (!(strcmp(yylval.str, "first")))
910 current_cfe->remote_numbers_handling = RNH_FIRST;
911 else
913 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"remdial_handling\" at line %d!", lineno);
914 config_error_flag++;
916 break;
918 case REMOTE_PHONE_INCOMING:
920 int n;
921 n = current_cfe->incoming_numbers_count;
922 if (n >= MAX_INCOMING)
924 logit(LL_ERR, "ERROR parsing config file: too many \"remote_phone_incoming\" entries at line %d!", lineno);
925 config_error_flag++;
926 break;
928 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: remote_phone_incoming #%d = %s", current_cfe->name, n, yylval.str)));
929 strlcpy(current_cfe->remote_phone_incoming[n].number,
930 yylval.str,
931 sizeof(current_cfe->remote_phone_incoming[n].number));
932 current_cfe->incoming_numbers_count++;
934 break;
936 case RATESFILE:
937 strlcpy(ratesfile, yylval.str, sizeof(ratesfile));
938 DBGL(DL_RCCF, (logit(LL_DBG, "system: ratesfile = %s", yylval.str)));
939 break;
941 case RATETYPE:
942 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: ratetype = %d", current_cfe->name, yylval.num)));
943 current_cfe->ratetype = yylval.num;
944 break;
946 case RECOVERYTIME:
947 if (yylval.num < RECOVERYTIME_MIN)
949 yylval.num = RECOVERYTIME_MIN;
950 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: recoverytime < %d, min = %d", current_cfe->name, RECOVERYTIME_MIN, yylval.num)));
953 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: recoverytime = %d", current_cfe->name, yylval.num)));
954 current_cfe->recoverytime = yylval.num;
955 break;
957 case REGEXPR:
958 if (nregexpr >= MAX_RE)
960 logit(LL_ERR, "system: regexpr #%d >= MAX_RE", nregexpr);
961 config_error_flag++;
962 break;
965 if ((i = regcomp(&(rarr[nregexpr].re), yylval.str, REG_EXTENDED|REG_NOSUB)) != 0)
967 char buf[256];
968 regerror(i, &(rarr[nregexpr].re), buf, sizeof(buf));
969 logit(LL_ERR, "system: regcomp error for %s: [%s]", yylval.str, buf);
970 config_error_flag++;
971 break;
973 else
975 if ((rarr[nregexpr].re_expr = strdup(yylval.str)) == NULL)
977 logit(LL_ERR, "system: regexpr malloc error error for %s", yylval.str);
978 config_error_flag++;
979 break;
982 DBGL(DL_RCCF, (logit(LL_DBG, "system: regexpr %s stored into slot %d", yylval.str, nregexpr)));
984 if (rarr[nregexpr].re_prog != NULL)
985 rarr[nregexpr].re_flg = 1;
987 nregexpr++;
990 break;
992 case REGPROG:
993 if (nregprog >= MAX_RE)
995 logit(LL_ERR, "system: regprog #%d >= MAX_RE", nregprog);
996 config_error_flag++;
997 break;
999 if ((rarr[nregprog].re_prog = strdup(yylval.str)) == NULL)
1001 logit(LL_ERR, "system: regprog malloc error error for %s", yylval.str);
1002 config_error_flag++;
1003 break;
1006 DBGL(DL_RCCF, (logit(LL_DBG, "system: regprog %s stored into slot %d", yylval.str, nregprog)));
1008 if (rarr[nregprog].re_expr != NULL)
1009 rarr[nregprog].re_flg = 1;
1011 nregprog++;
1012 break;
1014 case ROTATESUFFIX:
1015 strlcpy(rotatesuffix, yylval.str, sizeof(rotatesuffix));
1016 DBGL(DL_RCCF, (logit(LL_DBG, "system: rotatesuffix = %s", yylval.str)));
1017 break;
1019 case RTPRIO:
1020 #ifdef USE_RTPRIO
1021 rt_prio = yylval.num;
1022 if (rt_prio < RTP_PRIO_MIN || rt_prio > RTP_PRIO_MAX)
1024 config_error_flag++;
1025 logit(LL_ERR, "system: error, rtprio (%d) out of range!", yylval.num);
1027 else
1029 DBGL(DL_RCCF, (logit(LL_DBG, "system: rtprio = %d", yylval.num)));
1031 #else
1032 rt_prio = RTPRIO_NOTUSED;
1033 #endif
1034 break;
1036 case TINAINITPROG:
1037 strlcpy(tinainitprog, yylval.str, sizeof(tinainitprog));
1038 DBGL(DL_RCCF, (logit(LL_DBG, "system: tinainitprog = %s", yylval.str)));
1039 break;
1041 case UNITLENGTH:
1042 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: unitlength = %d", current_cfe->name, yylval.num)));
1043 current_cfe->unitlength = yylval.num;
1044 break;
1046 case UNITLENGTHSRC:
1047 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: unitlengthsrc = %s", current_cfe->name, yylval.str)));
1048 if (!(strcmp(yylval.str, "none")))
1049 current_cfe->unitlengthsrc = ULSRC_NONE;
1050 else if (!(strcmp(yylval.str, "cmdl")))
1051 current_cfe->unitlengthsrc = ULSRC_CMDL;
1052 else if (!(strcmp(yylval.str, "conf")))
1053 current_cfe->unitlengthsrc = ULSRC_CONF;
1054 else if (!(strcmp(yylval.str, "rate")))
1055 current_cfe->unitlengthsrc = ULSRC_RATE;
1056 else if (!(strcmp(yylval.str, "aocd")))
1057 current_cfe->unitlengthsrc = ULSRC_DYN;
1058 else
1060 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"unitlengthsrc\" at line %d!", lineno);
1061 config_error_flag++;
1063 break;
1065 case USRDEVICENAME:
1066 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: usrdevicename = %s", current_cfe->name, yylval.str)));
1067 strncpy(current_cfe->usrdevicename, yylval.str, sizeof(current_cfe->usrdevicename));
1068 current_cfe->usrdevice = lookup_l4_driver(yylval.str);
1069 if (current_cfe->usrdevice < 0)
1071 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"usrdevicename\" at line %d!", lineno);
1072 config_error_flag++;
1074 break;
1076 case USRDEVICEUNIT:
1077 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: usrdeviceunit = %d", current_cfe->name, yylval.num)));
1078 current_cfe->usrdeviceunit = yylval.num;
1079 break;
1081 case USEACCTFILE:
1082 useacctfile = yylval.booln;
1083 DBGL(DL_RCCF, (logit(LL_DBG, "system: useacctfile = %d", yylval.booln)));
1084 break;
1086 case USEDOWN:
1087 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: usedown = %d", current_cfe->name, yylval.booln)));
1088 current_cfe->usedown = yylval.booln;
1089 break;
1091 case VALID:
1092 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: valid = %s", current_cfe->name, yylval.str)));
1093 parse_valid(yylval.str);
1094 break;
1096 default:
1097 logit(LL_ERR, "ERROR parsing config file: unknown keyword at line %d!", lineno);
1098 config_error_flag++;
1099 break;
1103 /*---------------------------------------------------------------------------*
1104 * parse a date/time range
1105 *---------------------------------------------------------------------------*/
1106 static void
1107 parse_valid(char *dt)
1109 /* a valid string consists of some days of week separated by
1110 * commas, where 0=sunday, 1=monday .. 6=saturday and a special
1111 * value of 7 which is a holiday from the holiday file.
1112 * after the days comes an optional (!) time range in the form
1113 * aa:bb-cc:dd, this format is fixed to be parsable by sscanf.
1114 * Valid specifications looks like this:
1115 * 1,2,3,4,5,09:00-18:00 Monday-Friday 9-18h
1116 * 1,2,3,4,5,18:00-09:00 Monday-Friday 18-9h
1117 * 6 Saturday (whole day)
1118 * 0,7 Sunday and Holidays
1121 int day = 0;
1122 int fromhr = 0;
1123 int frommin = 0;
1124 int tohr = 0;
1125 int tomin = 0;
1126 int ret;
1128 for (;;)
1130 if ( ( ((*dt >= '0') && (*dt <= '9')) && (*(dt+1) == ':') ) ||
1131 ( ((*dt >= '0') && (*dt <= '2')) && ((*(dt+1) >= '0') && (*(dt+1) <= '9')) && (*(dt+2) == ':') ) )
1133 /* dt points to time spec */
1134 ret = sscanf(dt, "%d:%d-%d:%d", &fromhr, &frommin, &tohr, &tomin);
1135 if (ret !=4)
1137 logit(LL_ERR, "ERROR parsing config file: timespec [%s] error at line %d!", *dt, lineno);
1138 config_error_flag++;
1139 return;
1142 if (fromhr < 0 || fromhr > 24 || tohr < 0 || tohr > 24 ||
1143 frommin < 0 || frommin > 59 || tomin < 0 || tomin > 59)
1145 logit(LL_ERR, "ERROR parsing config file: invalid time [%s] at line %d!", *dt, lineno);
1146 config_error_flag++;
1147 return;
1149 break;
1151 else if ((*dt >= '0') && (*dt <= '7'))
1153 /* dt points to day spec */
1154 day |= 1 << (*dt - '0');
1155 dt++;
1156 continue;
1158 else if (*dt == ',')
1160 /* dt points to delimiter */
1161 dt++;
1162 continue;
1164 else if (*dt == '\0')
1166 /* dt points to end of string */
1167 break;
1169 else
1171 /* dt points to illegal character */
1172 logit(LL_ERR, "ERROR parsing config file: illegal character [%c=0x%x] in date/time spec at line %d!", *dt, *dt, lineno);
1173 config_error_flag++;
1174 return;
1177 current_cfe->day = day;
1178 current_cfe->fromhr = fromhr;
1179 current_cfe->frommin = frommin;
1180 current_cfe->tohr = tohr;
1181 current_cfe->tomin = tomin;
1184 void
1185 flush_config()
1187 if (current_cfe != NULL) {
1188 add_cfg_entry(current_cfe);
1192 /*---------------------------------------------------------------------------*
1193 * configuration validation and consistency check
1194 *---------------------------------------------------------------------------*/
1195 static void
1196 check_config(void)
1198 struct cfg_entry *cep = NULL;
1199 int i;
1200 int error = 0;
1202 /* regular expression table */
1204 for (i=0; i < MAX_RE; i++)
1206 if ((rarr[i].re_expr != NULL) && (rarr[i].re_prog == NULL))
1208 logit(LL_ERR, "check_config: regular expression %d without program!", i);
1209 error++;
1211 if ((rarr[i].re_prog != NULL) && (rarr[i].re_expr == NULL))
1213 logit(LL_ERR, "check_config: regular expression program %d without expression!", i);
1214 error++;
1218 /* entry sections */
1220 for (cep = get_first_cfg_entry(); cep; cep = NEXT_CFE(cep)) {
1222 /* does this entry have a bchannel driver configured? */
1223 if (cep->usrdevice < 0) {
1224 logit(LL_ERR, "check_config: usrdevicename not set in entry \"%s\"!",
1225 cep->name);
1226 error++;
1228 if (cep->usrdeviceunit < 0) {
1229 logit(LL_ERR, "check_config: usrdeviceunit not set in entry \"%s\"!",
1230 cep->name);
1231 error++;
1234 /* numbers used for dialout */
1236 if ((cep->inout != DIR_INONLY) && (cep->dialin_reaction != REACT_ANSWER))
1238 if (cep->remote_numbers_count == 0)
1240 logit(LL_ERR, "check_config: remote-phone-dialout not set in entry \"%s\"!",
1241 cep->name);
1242 error++;
1246 /* numbers used for incoming calls */
1248 if (cep->inout != DIR_OUTONLY)
1250 if (strlen(cep->local_phone_incoming) == 0)
1252 logit(LL_ERR, "check_config: local-phone-incoming not set in entry \"%s\"!",
1253 cep->name);
1254 error++;
1256 if (cep->incoming_numbers_count == 0)
1258 logit(LL_ERR, "check_config: remote-phone-incoming not set in entry \"%s\"!",
1259 cep->name);
1260 error++;
1264 if ((cep->dialin_reaction == REACT_ANSWER) && (cep->b1protocol != BPROT_NONE))
1266 logit(LL_ERR, "check_config: b1protocol not raw for telephony in entry \"%s\"!",
1267 cep->name);
1268 error++;
1271 if ((cep->ppp_send_auth == AUTH_PAP) || (cep->ppp_send_auth == AUTH_CHAP))
1273 if (cep->ppp_send_name == NULL)
1275 logit(LL_ERR, "check_config: no remote authentification name in entry \"%s\"!",
1276 cep->name);
1277 error++;
1279 if (cep->ppp_send_password == NULL)
1281 logit(LL_ERR, "check_config: no remote authentification password in entry \"%s\"!",
1282 cep->name);
1283 error++;
1286 if ((cep->ppp_expect_auth == AUTH_PAP) || (cep->ppp_expect_auth == AUTH_CHAP))
1288 if (cep->ppp_expect_name == NULL)
1290 logit(LL_ERR, "check_config: no local authentification name in entry \"%s\"!",
1291 cep->name);
1292 error++;
1294 if (cep->ppp_expect_password == NULL)
1296 logit(LL_ERR, "check_config: no local authentification secret in entry \"%s\"!",
1297 cep->name);
1298 error++;
1302 if (cep->ppp_expect_auth != AUTH_UNDEF
1303 || cep->ppp_send_auth != AUTH_UNDEF)
1304 set_isppp_auth(cep);
1307 * Only if AUTOUPDOWN_YES is the only bit set, otherwise
1308 * we already have handled this interface.
1310 if (cep->autoupdown == AUTOUPDOWN_YES)
1311 set_autoupdown(cep);
1313 if (error) {
1314 logit(LL_ERR, "check_config: %d error(s) in configuration file, exiting!",
1315 error);
1316 do_exit(1);
1320 /*---------------------------------------------------------------------------*
1321 * print the configuration
1322 *---------------------------------------------------------------------------*/
1323 static void
1324 print_config(void)
1326 #define PFILE stdout
1328 #ifdef I4B_EXTERNAL_MONITOR
1329 extern struct monitor_rights * monitor_next_rights(const struct monitor_rights *r);
1330 struct monitor_rights *m_rights;
1331 #endif
1332 struct cfg_entry *cep = NULL;
1333 int i, j;
1334 time_t now;
1335 char mytime[64];
1337 time(&now);
1338 strlcpy(mytime, ctime(&now), sizeof(mytime));
1339 mytime[strlen(mytime)-1] = '\0';
1341 fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1342 fprintf(PFILE, "# system section (generated %s)\n", mytime);
1343 fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1344 fprintf(PFILE, "system\n");
1345 fprintf(PFILE, "useacctfile = %s\n", useacctfile ? "on\t\t\t\t# update accounting information file" : "off\t\t\t\t# don't update accounting information file");
1346 fprintf(PFILE, "acctall = %s\n", acct_all ? "on\t\t\t\t# put all events into accounting file" : "off\t\t\t\t# put only charged events into accounting file");
1347 fprintf(PFILE, "acctfile = %s\t\t# accounting information file\n", acctfile);
1348 fprintf(PFILE, "ratesfile = %s\t\t# charging rates database file\n", ratesfile);
1350 #ifdef USE_RTPRIO
1351 if (rt_prio == RTPRIO_NOTUSED)
1352 fprintf(PFILE, "# rtprio is unused\n");
1353 else
1354 fprintf(PFILE, "rtprio = %d\t\t\t\t# isdnd runs at realtime priority\n", rt_prio);
1355 #endif
1357 /* regular expression table */
1359 for (i=0; i < MAX_RE; i++)
1361 if (rarr[i].re_expr != NULL)
1363 fprintf(PFILE, "regexpr = \"%s\"\t\t# scan logfile for this expression\n", rarr[i].re_expr);
1365 if (rarr[i].re_prog != NULL)
1367 fprintf(PFILE, "regprog = %s\t\t# program to run when expression is matched\n", rarr[i].re_prog);
1371 #ifdef I4B_EXTERNAL_MONITOR
1373 fprintf(PFILE, "monitor-allowed = %s\n", do_monitor ? "on\t\t\t\t# remote isdnd monitoring allowed" : "off\t\t\t\t# remote isdnd monitoring disabled");
1374 fprintf(PFILE, "monitor-port = %d\t\t\t\t# TCP/IP port number used for remote monitoring\n", monitorport);
1376 m_rights = monitor_next_rights(NULL);
1377 if (m_rights != NULL)
1379 const char *s = "error\n";
1380 char b[512];
1382 for ( ; m_rights != NULL; m_rights = monitor_next_rights(m_rights))
1384 if (m_rights->local)
1386 fprintf(PFILE, "monitor = \"%s\"\t\t# local socket name for monitoring\n", m_rights->name);
1388 else
1390 struct in_addr ia;
1391 ia.s_addr = ntohl(m_rights->net);
1393 switch (m_rights->mask)
1395 case 0xffffffff:
1396 s = "32";
1397 break;
1398 case 0xfffffffe:
1399 s = "31";
1400 break;
1401 case 0xfffffffc:
1402 s = "30";
1403 break;
1404 case 0xfffffff8:
1405 s = "29";
1406 break;
1407 case 0xfffffff0:
1408 s = "28";
1409 break;
1410 case 0xffffffe0:
1411 s = "27";
1412 break;
1413 case 0xffffffc0:
1414 s = "26";
1415 break;
1416 case 0xffffff80:
1417 s = "25";
1418 break;
1419 case 0xffffff00:
1420 s = "24";
1421 break;
1422 case 0xfffffe00:
1423 s = "23";
1424 break;
1425 case 0xfffffc00:
1426 s = "22";
1427 break;
1428 case 0xfffff800:
1429 s = "21";
1430 break;
1431 case 0xfffff000:
1432 s = "20";
1433 break;
1434 case 0xffffe000:
1435 s = "19";
1436 break;
1437 case 0xffffc000:
1438 s = "18";
1439 break;
1440 case 0xffff8000:
1441 s = "17";
1442 break;
1443 case 0xffff0000:
1444 s = "16";
1445 break;
1446 case 0xfffe0000:
1447 s = "15";
1448 break;
1449 case 0xfffc0000:
1450 s = "14";
1451 break;
1452 case 0xfff80000:
1453 s = "13";
1454 break;
1455 case 0xfff00000:
1456 s = "12";
1457 break;
1458 case 0xffe00000:
1459 s = "11";
1460 break;
1461 case 0xffc00000:
1462 s = "10";
1463 break;
1464 case 0xff800000:
1465 s = "9";
1466 break;
1467 case 0xff000000:
1468 s = "8";
1469 break;
1470 case 0xfe000000:
1471 s = "7";
1472 break;
1473 case 0xfc000000:
1474 s = "6";
1475 break;
1476 case 0xf8000000:
1477 s = "5";
1478 break;
1479 case 0xf0000000:
1480 s = "4";
1481 break;
1482 case 0xe0000000:
1483 s = "3";
1484 break;
1485 case 0xc0000000:
1486 s = "2";
1487 break;
1488 case 0x80000000:
1489 s = "1";
1490 break;
1491 case 0x00000000:
1492 s = "0";
1493 break;
1495 fprintf(PFILE, "monitor = \"%s/%s\"\t\t# host (net/mask) allowed to connect for monitoring\n", inet_ntoa(ia), s);
1497 b[0] = '\0';
1499 if ((m_rights->rights) & I4B_CA_COMMAND_FULL)
1500 strlcat(b, "fullcmd,", sizeof(b));
1501 if ((m_rights->rights) & I4B_CA_COMMAND_RESTRICTED)
1502 strlcat(b, "restrictedcmd,", sizeof(b));
1503 if ((m_rights->rights) & I4B_CA_EVNT_CHANSTATE)
1504 strlcat(b, "channelstate,", sizeof(b));
1505 if ((m_rights->rights) & I4B_CA_EVNT_CALLIN)
1506 strlcat(b, "callin,", sizeof(b));
1507 if ((m_rights->rights) & I4B_CA_EVNT_CALLOUT)
1508 strlcat(b, "callout,", sizeof(b));
1509 if ((m_rights->rights) & I4B_CA_EVNT_I4B)
1510 strlcat(b, "logevents,", sizeof(b));
1512 if (strlen(b) > 0 && b[strlen(b)-1] == ',')
1513 b[strlen(b)-1] = '\0';
1515 fprintf(PFILE, "monitor-access = %s\t\t# monitor access rights\n", b);
1519 #endif
1520 /* entry sections */
1522 for (cep = get_first_cfg_entry(); cep; cep = NEXT_CFE(cep)) {
1523 fprintf(PFILE, "\n");
1524 fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1525 fprintf(PFILE, "# entry section %d\n", i);
1526 fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1527 fprintf(PFILE, "entry\n");
1529 fprintf(PFILE, "name = %s\t\t# name for this entry section\n", cep->name);
1531 fprintf(PFILE, "isdncontroller = %d\t\t# ISDN card number used for this entry\n", cep->isdncontroller);
1532 fprintf(PFILE, "isdnchannel = ");
1533 switch (cep->isdnchannel)
1535 case CHAN_ANY:
1536 fprintf(PFILE, "-1\t\t# any ISDN B-channel may be used\n");
1537 break;
1538 default:
1539 fprintf(PFILE, "1\t\t# only ISDN B-channel %d may be used\n", cep->isdnchannel);
1540 break;
1543 fprintf(PFILE, "usrdevicename = %s\t\t# name of userland ISDN B-channel device\n", cep->usrdevicename);
1544 fprintf(PFILE, "usrdeviceunit = %d\t\t# unit number of userland ISDN B-channel device\n", cep->usrdeviceunit);
1546 fprintf(PFILE, "b1protocol = %s\n", cep->b1protocol ? "hdlc\t\t# B-channel layer 1 protocol is HDLC" : "raw\t\t# No B-channel layer 1 protocol used");
1548 fprintf(PFILE, "direction = ");
1549 switch (cep->inout)
1551 case DIR_INONLY:
1552 fprintf(PFILE, "in\t\t# only incoming connections allowed\n");
1553 break;
1554 case DIR_OUTONLY:
1555 fprintf(PFILE, "out\t\t# only outgoing connections allowed\n");
1556 break;
1557 case DIR_INOUT:
1558 fprintf(PFILE, "inout\t\t# incoming and outgoing connections allowed\n");
1559 break;
1562 if (cep->remote_numbers_count > 1)
1564 for (j = 0; j < cep->remote_numbers_count; j++)
1565 fprintf(PFILE, "remote-phone-dialout = %s\t\t# telephone number %d for dialing out to remote\n", cep->remote_numbers[j].number, j+1);
1567 fprintf(PFILE, "remdial-handling = ");
1569 switch (cep->remote_numbers_handling)
1571 case RNH_NEXT:
1572 fprintf(PFILE, "next\t\t# use next number after last successful for new dial\n");
1573 break;
1574 case RNH_LAST:
1575 fprintf(PFILE, "last\t\t# use last successful number for new dial\n");
1576 break;
1577 case RNH_FIRST:
1578 fprintf(PFILE, "first\t\t# always start with first number for new dial\n");
1579 break;
1583 if (cep->local_phone_dialout[0])
1584 fprintf(PFILE, "local-phone-dialout = %s\t\t# show this number to remote when dialling out\n",
1585 cep->local_phone_dialout);
1586 fprintf(PFILE, "dialout-type = %s\n", cep->dialouttype ? "calledback\t\t# i am called back by remote" : "normal\t\t# i am not called back by remote");
1589 if (!(cep->inout == DIR_OUTONLY))
1591 int n;
1593 fprintf(PFILE, "local-phone-incoming = %s\t\t# incoming calls must match this (mine) telephone number\n", cep->local_phone_incoming);
1594 for (n = 0; n < cep->incoming_numbers_count; n++)
1595 fprintf(PFILE, "remote-phone-incoming = %s\t\t# this is a valid remote number to call me\n",
1596 cep->remote_phone_incoming[n].number);
1598 fprintf(PFILE, "dialin-reaction = ");
1599 switch (cep->dialin_reaction)
1601 case REACT_ACCEPT:
1602 fprintf(PFILE, "accept\t\t# i accept a call from remote and connect\n");
1603 break;
1604 case REACT_REJECT:
1605 fprintf(PFILE, "reject\t\t# i reject the call from remote\n");
1606 break;
1607 case REACT_IGNORE:
1608 fprintf(PFILE, "ignore\t\t# i ignore the call from remote\n");
1609 break;
1610 case REACT_ANSWER:
1611 fprintf(PFILE, "answer\t\t# i will start telephone answering when remote calls in\n");
1612 break;
1613 case REACT_CALLBACK:
1614 fprintf(PFILE, "callback\t\t# when remote calls in, i will hangup and call back\n");
1615 break;
1620 const char *s;
1621 switch (cep->ppp_expect_auth)
1623 case AUTH_NONE:
1624 s = "none";
1625 break;
1626 case AUTH_PAP:
1627 s = "pap";
1628 break;
1629 case AUTH_CHAP:
1630 s = "chap";
1631 break;
1632 default:
1633 s = NULL;
1634 break;
1636 if (s != NULL)
1638 fprintf(PFILE, "ppp-expect-auth = %s\t\t# the auth protocol we expect to receive on dial-in (none,pap,chap)\n", s);
1639 if (cep->ppp_expect_auth != AUTH_NONE)
1641 fprintf(PFILE, "ppp-expect-name = %s\t\t# the user name allowed in\n", cep->ppp_expect_name);
1642 fprintf(PFILE, "ppp-expect-password = %s\t\t# the key expected from the other side\n", cep->ppp_expect_password);
1643 fprintf(PFILE, "ppp-auth-paranoid = %s\t\t# do we require remote to authenticate even if we dial out\n", cep->ppp_auth_flags & AUTH_REQUIRED ? "yes" : "no");
1646 switch (cep->ppp_send_auth)
1648 case AUTH_NONE:
1649 s = "none";
1650 break;
1651 case AUTH_PAP:
1652 s = "pap";
1653 break;
1654 case AUTH_CHAP:
1655 s = "chap";
1656 break;
1657 default:
1658 s = NULL;
1659 break;
1661 if (s != NULL)
1663 fprintf(PFILE, "ppp-send-auth = %s\t\t# the auth protocol we use when dialing out (none,pap,chap)\n", s);
1664 if (cep->ppp_send_auth != AUTH_NONE)
1666 fprintf(PFILE, "ppp-send-name = %s\t\t# our PPP account used for dial-out\n", cep->ppp_send_name);
1667 fprintf(PFILE, "ppp-send-password = %s\t\t# the key sent to the other side\n", cep->ppp_send_password);
1670 if (cep->ppp_send_auth == AUTH_CHAP ||
1671 cep->ppp_expect_auth == AUTH_CHAP) {
1672 fprintf(PFILE, "ppp-auth-rechallenge = %s\t\t# rechallenge CHAP connections once in a while\n", cep->ppp_auth_flags & AUTH_RECHALLENGE ? "yes" : "no");
1676 if (cep->autoupdown == AUTOUPDOWN_NO)
1677 fprintf(PFILE, "autoupdown = no\n");
1680 const char *s;
1681 fprintf(PFILE, "idletime-outgoing = %d\t\t# outgoing call idle timeout\n", cep->idle_time_out);
1683 switch ( cep->shorthold_algorithm )
1685 case SHA_FIXU:
1686 s = "fix-unit-size";
1687 break;
1688 case SHA_VARU:
1689 s = "var-unit-size";
1690 break;
1691 default:
1692 s = "error!!!";
1693 break;
1696 fprintf(PFILE, "idle-algorithm-outgoing = %s\t\t# outgoing call idle algorithm\n", s);
1699 if (!(cep->inout == DIR_OUTONLY))
1700 fprintf(PFILE, "idletime-incoming = %d\t\t# incoming call idle timeout\n", cep->idle_time_in);
1703 fprintf(PFILE, "unitlengthsrc = ");
1704 switch (cep->unitlengthsrc)
1706 case ULSRC_NONE:
1707 fprintf(PFILE, "none\t\t# no unit length specified, using default\n");
1708 break;
1709 case ULSRC_CMDL:
1710 fprintf(PFILE, "cmdl\t\t# using unit length specified on commandline\n");
1711 break;
1712 case ULSRC_CONF:
1713 fprintf(PFILE, "conf\t\t# using unitlength specified by unitlength-keyword\n");
1714 fprintf(PFILE, "unitlength = %d\t\t# fixed unitlength\n", cep->unitlength);
1715 break;
1716 case ULSRC_RATE:
1717 fprintf(PFILE, "rate\t\t# using unitlength specified in rate database\n");
1718 fprintf(PFILE, "ratetype = %d\t\t# type of rate from rate database\n", cep->ratetype);
1719 break;
1720 case ULSRC_DYN:
1721 fprintf(PFILE, "aocd\t\t# using dynamically calculated unitlength based on AOCD subscription\n");
1722 fprintf(PFILE, "ratetype = %d\t\t# type of rate from rate database\n", cep->ratetype);
1723 break;
1726 fprintf(PFILE, "earlyhangup = %d\t\t# early hangup safety time\n", cep->earlyhangup);
1731 fprintf(PFILE, "answerprog = %s\t\t# program used to answer incoming telephone calls\n", cep->answerprog);
1732 fprintf(PFILE, "alert = %d\t\t# number of seconds to wait before accepting a call\n", cep->alert);
1736 if (cep->dialin_reaction == REACT_CALLBACK)
1737 fprintf(PFILE, "callbackwait = %d\t\t# i am waiting this time before calling back remote\n", cep->callbackwait);
1739 if (cep->dialouttype == DIALOUT_CALLEDBACK)
1740 fprintf(PFILE, "calledbackwait = %d\t\t# i am waiting this time for a call back from remote\n", cep->calledbackwait);
1742 if (!(cep->inout == DIR_INONLY))
1744 fprintf(PFILE, "dialretries = %d\t\t# number of dialing retries\n", cep->dialretries);
1745 fprintf(PFILE, "recoverytime = %d\t\t# time to wait between dialling retries\n", cep->recoverytime);
1746 fprintf(PFILE, "dialrandincr = %s\t\t# use random dialing time addon\n", cep->dialrandincr ? "on" : "off");
1748 fprintf(PFILE, "usedown = %s\n", cep->usedown ? "on\t\t# ISDN device switched off on excessive dial failures" : "off\t\t# no device switchoff on excessive dial failures");
1749 if (cep->usedown)
1751 fprintf(PFILE, "downtries = %d\t\t# number of dialretries failures before switching off\n", cep->downtries);
1752 fprintf(PFILE, "downtime = %d\t\t# time device is switched off\n", cep->downtime);
1756 fprintf(PFILE, "\n");
1759 static int
1760 lookup_l4_driver(const char *name)
1762 msg_l4driver_lookup_t query;
1763 int e;
1765 memset(&query, 0, sizeof query);
1766 strncpy(query.name, name, sizeof query.name);
1767 e = ioctl(isdnfd, I4B_L4DRIVER_LOOKUP, &query);
1768 if (e != 0) return -1;
1769 return query.driver_id;