1/* 2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved. 3 * 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. 12 * 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. 24 * 25 *--------------------------------------------------------------------------- 26 * 27 * i4b daemon - config file processing 28 * ----------------------------------- 29 * 30 * $Id: rc_config.c,v 1.25 2009/04/16 05:56:32 lukem Exp $ 31 * 32 * $FreeBSD$ 33 * 34 * last edit-date: [Sat Jan 6 12:57:36 2001] 35 * 36 *---------------------------------------------------------------------------*/ 37 38#include <sys/types.h> 39#include <sys/socket.h> 40#include <netinet/in.h> 41#include <arpa/inet.h> 42 43#include <sys/callout.h> 44#include <sys/ioctl.h> 45#include <ifaddrs.h> 46 47#include "isdnd.h" 48#include "rc_parse.h" 49 50#include "monitor.h" 51 52extern int lineno; 53extern char *yytext; 54 55extern FILE *yyin; 56extern int yyparse(void); 57 58static void set_config_defaults(void); 59static void check_config(void); 60static void print_config(void); 61static void parse_valid(char *dt); 62static int lookup_l4_driver(const char *name); 63void init_currrent_cfg_state(void); 64static void set_isppp_auth(struct cfg_entry*); 65static void set_autoupdown(struct cfg_entry*); 66void flush_config(void); 67 68static int nregexpr = 0; 69static int nregprog = 0; 70static struct cfg_entry * current_cfe = NULL; 71struct isdn_ctrl_state * cur_ctrl = NULL; 72 73/*---------------------------------------------------------------------------* 74 * called from main to read and process config file 75 *---------------------------------------------------------------------------*/ 76void 77configure(const char *filename, int reread) 78{ 79 extern void reset_scanner(FILE *inputfile); 80 81 set_config_defaults(); 82 83 yyin = fopen(filename, "r"); 84 85 if (reread) 86 { 87 reset_scanner(yyin); 88 current_cfe = NULL; 89 } 90 91 if (yyin == NULL) 92 { 93 logit(LL_ERR, "cannot fopen file [%s]", filename); 94 exit(1); 95 } 96 97 yyparse(); 98 99 monitor_fixup_rights(); 100 101 check_config(); /* validation and consistency check */ 102 103 fclose(yyin); 104 105 if (do_print) 106 { 107 if (config_error_flag) 108 { 109 logit(LL_ERR, "there were %d error(s) in the configuration file, terminating!", config_error_flag); 110 exit(1); 111 } 112 print_config(); 113 do_exit(0); 114 } 115} 116 117/*---------------------------------------------------------------------------* 118 * yacc error routine 119 *---------------------------------------------------------------------------*/ 120void 121yyerror(const char *msg) 122{ 123 logit(LL_ERR, "configuration error: %s at line %d, token \"%s\"", msg, lineno+1, yytext); 124 config_error_flag++; 125} 126 127/* 128 * Prepare a new default entry 129 */ 130void 131init_currrent_cfg_state() 132{ 133 if (current_cfe != NULL) { 134 add_cfg_entry(current_cfe); 135 } 136 current_cfe = malloc(sizeof(struct cfg_entry)); 137 memset(current_cfe, 0, sizeof(struct cfg_entry)); 138 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; 164} 165 166/*---------------------------------------------------------------------------* 167 * fill all config entries with default values 168 *---------------------------------------------------------------------------*/ 169static void 170set_config_defaults(void) 171{ 172 int i; 173 174 /* system section cleanup */ 175 176 nregprog = nregexpr = 0; 177 178 rt_prio = RTPRIO_NOTUSED; 179 180 mailer[0] = '\0'; 181 mailto[0] = '\0'; 182 183 /* clean regular expression table */ 184 185 for (i=0; i < MAX_RE; i++) 186 { 187 if (rarr[i].re_expr) 188 free(rarr[i].re_expr); 189 rarr[i].re_expr = NULL; 190 191 if (rarr[i].re_prog) 192 free(rarr[i].re_prog); 193 rarr[i].re_prog = NULL; 194 195 rarr[i].re_flg = 0; 196 } 197 198 strlcpy(rotatesuffix, "", sizeof(rotatesuffix)); 199} 200 201static void 202set_autoupdown(struct cfg_entry *cep) 203{ 204 struct ifaddrs *res = NULL, *p; 205 struct ifreq ifr; 206 int r, s, cnt, in6; 207 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); 212 213 /* 214 * See if this interface has got any valid addresses - if not, 215 * leave it alone. 216 */ 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++; 230 } 231 freeifaddrs(res); 232 } 233 234 if (in6) 235 cnt--; /* XXX - heuristic to adjust for INET6 local scope */ 236 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; 243 } 244 } 245 246 close(s); 247} 248 249static void 250set_isppp_auth(struct cfg_entry *cep) 251{ 252 struct spppauthcfg spcfg; 253 int s; 254 int doioctl = 0; 255 256 if (cep->ppp_expect_auth == AUTH_UNDEF 257 && cep->ppp_send_auth == AUTH_UNDEF) 258 return; 259 260 if (cep->ppp_expect_auth == AUTH_NONE 261 || cep->ppp_send_auth == AUTH_NONE) 262 doioctl = 1; 263 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; 269 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; 274 275 if (!doioctl) 276 return; 277 278 memset(&spcfg, 0, sizeof spcfg); 279 snprintf(spcfg.ifname, sizeof(spcfg.ifname), "%s%d", 280 cep->usrdevicename, cep->usrdeviceunit); 281 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; 287 } 288 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; 294 } 295 if (cep->ppp_expect_auth != AUTH_UNDEF) 296 { 297 if (cep->ppp_expect_auth == AUTH_NONE) 298 { 299 spcfg.hisauth = SPPP_AUTHPROTO_NONE; 300 } 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) 305 { 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; 311 } 312 } 313 if (cep->ppp_send_auth != AUTH_UNDEF) 314 { 315 if (cep->ppp_send_auth == AUTH_NONE) 316 { 317 spcfg.myauth = SPPP_AUTHPROTO_NONE; 318 } 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) 323 { 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; 329 330 if (cep->ppp_auth_flags & AUTH_REQUIRED) 331 spcfg.hisauthflags &= ~SPPP_AUTHFLAG_NOCALLOUT; 332 else 333 spcfg.hisauthflags |= SPPP_AUTHFLAG_NOCALLOUT; 334 335 if (cep->ppp_auth_flags & AUTH_RECHALLENGE) 336 spcfg.hisauthflags &= ~SPPP_AUTHFLAG_NORECHALLENGE; 337 else 338 spcfg.hisauthflags |= SPPP_AUTHFLAG_NORECHALLENGE; 339 } 340 } 341 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++; 345 } 346 close(s); 347} 348 349/*---------------------------------------------------------------------------* 350 * extract values from config and fill table 351 *---------------------------------------------------------------------------*/ 352void 353cfg_setval(int keyword) 354{ 355 int i; 356 357 switch (keyword) 358 { 359 case ACCTALL: 360 acct_all = yylval.booln; 361 DBGL(DL_RCCF, (logit(LL_DBG, "system: acctall = %d", yylval.booln))); 362 break; 363 364 case ACCTFILE: 365 strlcpy(acctfile, yylval.str, sizeof(acctfile)); 366 DBGL(DL_RCCF, (logit(LL_DBG, "system: acctfile = %s", yylval.str))); 367 break; 368 369 case ALERT: 370 if (yylval.num < MINALERT) 371 { 372 yylval.num = MINALERT; 373 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: alert < %d, min = %d", current_cfe->name, MINALERT, yylval.num))); 374 } 375 else if (yylval.num > MAXALERT) 376 { 377 yylval.num = MAXALERT; 378 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: alert > %d, min = %d", current_cfe->name, MAXALERT, yylval.num))); 379 } 380 381 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: alert = %d", current_cfe->name, yylval.num))); 382 current_cfe->alert = yylval.num; 383 break; 384 385 case ALIASING: 386 DBGL(DL_RCCF, (logit(LL_DBG, "system: aliasing = %d", yylval.booln))); 387 aliasing = yylval.booln; 388 break; 389 390 case ALIASFNAME: 391 strlcpy(aliasfile, yylval.str, sizeof(aliasfile)); 392 DBGL(DL_RCCF, (logit(LL_DBG, "system: aliasfile = %s", yylval.str))); 393 break; 394 395 case ANSWERPROG: 396 if ((current_cfe->answerprog = strdup(yylval.str)) == NULL) 397 { 398 logit(LL_ERR, "entry %s: answerstring, malloc failed!", current_cfe->name); 399 do_exit(1); 400 } 401 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: answerprog = %s", current_cfe->name, yylval.str))); 402 break; 403 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 411 { 412 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"b1protocol\" at line %d!", lineno); 413 config_error_flag++; 414 } 415 break; 416 417 case BEEPCONNECT: 418 do_bell = yylval.booln; 419 DBGL(DL_RCCF, (logit(LL_DBG, "system: beepconnect = %d", yylval.booln))); 420 break; 421 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; 426 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; 431 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; 436 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; 441 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; 446 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; 451 452 case BUDGETCALLBACKSFILE: 453 { 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) 460 { 461 if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) != 3) 462 { 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); 469 } 470 } else 471 fclose(fp); 472 } 473 else 474 { 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); 480 } 481 482 fp = fopen(yylval.str, "r"); 483 if (fp != NULL) 484 { 485 if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) == 3) 486 { 487 if ((current_cfe->budget_callbacks_file = strdup(yylval.str)) == NULL) 488 { 489 logit(LL_ERR, "entry %s: budget-callbacksfile, malloc failed!", current_cfe->name); 490 do_exit(1); 491 } 492 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: using callbacksfile %s", current_cfe->name, yylval.str))); 493 } 494 fclose(fp); 495 } 496 } 497 break; 498 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; 503 504 case BUDGETCALLOUTSFILE: 505 { 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) 512 { 513 if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) != 3) 514 { 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); 521 } 522 } 523 else 524 { 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); 530 } 531 532 fp = fopen(yylval.str, "r"); 533 if (fp != NULL) 534 { 535 if ((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) == 3) 536 { 537 if ((current_cfe->budget_callouts_file = strdup(yylval.str)) == NULL) 538 { 539 logit(LL_ERR, "entry %s: budget-calloutsfile, malloc failed!", current_cfe->name); 540 do_exit(1); 541 } 542 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: using calloutsfile %s", current_cfe->name, yylval.str))); 543 } 544 fclose(fp); 545 } 546 } 547 break; 548 549 case CALLBACKWAIT: 550 if (yylval.num < CALLBACKWAIT_MIN) 551 { 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))); 554 } 555 556 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: callbackwait = %d", current_cfe->name, yylval.num))); 557 current_cfe->callbackwait = yylval.num; 558 break; 559 560 case CALLEDBACKWAIT: 561 if (yylval.num < CALLEDBACKWAIT_MIN) 562 { 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))); 565 } 566 567 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: calledbackwait = %d", current_cfe->name, yylval.num))); 568 current_cfe->calledbackwait = yylval.num; 569 break; 570 571 case CONNECTPROG: 572 if ((current_cfe->connectprog = strdup(yylval.str)) == NULL) 573 { 574 logit(LL_ERR, "entry %s: connectprog, malloc failed!", current_cfe->name); 575 do_exit(1); 576 } 577 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: connectprog = %s", current_cfe->name, yylval.str))); 578 break; 579 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 587 { 588 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"dialout-type\" at line %d!", lineno); 589 config_error_flag++; 590 } 591 break; 592 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; 597 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; 602 603 case DIRECTION: 604 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: direction = %s", current_cfe->name, yylval.str))); 605 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 613 { 614 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"direction\" at line %d!", lineno); 615 config_error_flag++; 616 } 617 break; 618 619 case DISCONNECTPROG: 620 if ((current_cfe->disconnectprog = strdup(yylval.str)) == NULL) 621 { 622 logit(LL_ERR, "entry %s: disconnectprog, malloc failed!", current_cfe->name); 623 do_exit(1); 624 } 625 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: disconnectprog = %s", current_cfe->name, yylval.str))); 626 break; 627 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; 633 634 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: downtries = %d", current_cfe->name, yylval.num))); 635 current_cfe->downtries = yylval.num; 636 break; 637 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; 643 644 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: downtime = %d", current_cfe->name, yylval.num))); 645 current_cfe->downtime = yylval.num; 646 break; 647 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; 652 653 case EXTCALLATTR: 654 DBGL(DL_RCCF, (logit(LL_DBG, "system: extcallattr = %d", yylval.booln))); 655 extcallattr = yylval.booln; 656 break; 657 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; 662 663 case HOLIDAYFILE: 664 strlcpy(holidayfile, yylval.str, sizeof(holidayfile)); 665 DBGL(DL_RCCF, (logit(LL_DBG, "system: holidayfile = %s", yylval.str))); 666 break; 667 668 case IDLE_ALG_OUT: 669 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: idle-algorithm-outgoing = %s", current_cfe->name, yylval.str))); 670 671 if (!(strcmp(yylval.str, "fix-unit-size"))) 672 { 673 current_cfe->shorthold_algorithm = SHA_FIXU; 674 } 675 else if (!(strcmp(yylval.str, "var-unit-size"))) 676 { 677 current_cfe->shorthold_algorithm = SHA_VARU; 678 } 679 else 680 { 681 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"idle-algorithm-outgoing\" at line %d!", lineno); 682 config_error_flag++; 683 } 684 break; 685 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; 690 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; 695 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; 700 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))); 711 } 712 break; 713 714 case ISDNTIME: 715 DBGL(DL_RCCF, (logit(LL_DBG, "system: isdntime = %d", yylval.booln))); 716 isdntime = yylval.booln; 717 break; 718 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; 723 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; 728 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; 734 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; 740 741 case MAILER: 742 strlcpy(mailer, yylval.str, sizeof(mailer)); 743 DBGL(DL_RCCF, (logit(LL_DBG, "system: mailer = %s", yylval.str))); 744 break; 745 746 case MAILTO: 747 strlcpy(mailto, yylval.str, sizeof(mailto)); 748 DBGL(DL_RCCF, (logit(LL_DBG, "system: mailto = %s", yylval.str))); 749 break; 750 751 case MONITORPORT: 752 monitorport = yylval.num; 753 DBGL(DL_RCCF, (logit(LL_DBG, "system: monitorport = %d", yylval.num))); 754 break; 755 756 case MONITORSW: 757 if (yylval.booln && inhibit_monitor) 758 { 759 do_monitor = 0; 760 DBGL(DL_RCCF, (logit(LL_DBG, "system: monitor-enable overriden by command line flag"))); 761 } 762 else 763 { 764 do_monitor = yylval.booln; 765 DBGL(DL_RCCF, (logit(LL_DBG, "system: monitor-enable = %d", yylval.booln))); 766 } 767 break; 768 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; 774 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; 782 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; 790 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 800 { 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; 804 } 805 break; 806 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; 813 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; 820 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 830 { 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; 834 } 835 break; 836 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; 843 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; 850 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 858 { 859 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"protocol\" at line %d!", lineno); 860 config_error_flag++; 861 } 862 break; 863 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 877 { 878 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"dialin_reaction\" at line %d!", lineno); 879 config_error_flag++; 880 } 881 break; 882 883 case REMOTE_PHONE_DIALOUT: 884 if (current_cfe->remote_numbers_count >= MAXRNUMBERS) 885 { 886 logit(LL_ERR, "ERROR parsing config file: too many remote numbers at line %d!", lineno); 887 config_error_flag++; 888 break; 889 } 890 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))); 893 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; 898 899 current_cfe->remote_numbers_count++; 900 901 break; 902 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 912 { 913 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"remdial_handling\" at line %d!", lineno); 914 config_error_flag++; 915 } 916 break; 917 918 case REMOTE_PHONE_INCOMING: 919 { 920 int n; 921 n = current_cfe->incoming_numbers_count; 922 if (n >= MAX_INCOMING) 923 { 924 logit(LL_ERR, "ERROR parsing config file: too many \"remote_phone_incoming\" entries at line %d!", lineno); 925 config_error_flag++; 926 break; 927 } 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++; 933 } 934 break; 935 936 case RATESFILE: 937 strlcpy(ratesfile, yylval.str, sizeof(ratesfile)); 938 DBGL(DL_RCCF, (logit(LL_DBG, "system: ratesfile = %s", yylval.str))); 939 break; 940 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; 945 946 case RECOVERYTIME: 947 if (yylval.num < RECOVERYTIME_MIN) 948 { 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))); 951 } 952 953 DBGL(DL_RCCF, (logit(LL_DBG, "entry %s: recoverytime = %d", current_cfe->name, yylval.num))); 954 current_cfe->recoverytime = yylval.num; 955 break; 956 957 case REGEXPR: 958 if (nregexpr >= MAX_RE) 959 { 960 logit(LL_ERR, "system: regexpr #%d >= MAX_RE", nregexpr); 961 config_error_flag++; 962 break; 963 } 964 965 if ((i = regcomp(&(rarr[nregexpr].re), yylval.str, REG_EXTENDED|REG_NOSUB)) != 0) 966 { 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; 972 } 973 else 974 { 975 if ((rarr[nregexpr].re_expr = strdup(yylval.str)) == NULL) 976 { 977 logit(LL_ERR, "system: regexpr malloc error error for %s", yylval.str); 978 config_error_flag++; 979 break; 980 } 981 982 DBGL(DL_RCCF, (logit(LL_DBG, "system: regexpr %s stored into slot %d", yylval.str, nregexpr))); 983 984 if (rarr[nregexpr].re_prog != NULL) 985 rarr[nregexpr].re_flg = 1; 986 987 nregexpr++; 988 989 } 990 break; 991 992 case REGPROG: 993 if (nregprog >= MAX_RE) 994 { 995 logit(LL_ERR, "system: regprog #%d >= MAX_RE", nregprog); 996 config_error_flag++; 997 break; 998 } 999 if ((rarr[nregprog].re_prog = strdup(yylval.str)) == NULL) 1000 { 1001 logit(LL_ERR, "system: regprog malloc error error for %s", yylval.str); 1002 config_error_flag++; 1003 break; 1004 } 1005 1006 DBGL(DL_RCCF, (logit(LL_DBG, "system: regprog %s stored into slot %d", yylval.str, nregprog))); 1007 1008 if (rarr[nregprog].re_expr != NULL) 1009 rarr[nregprog].re_flg = 1; 1010 1011 nregprog++; 1012 break; 1013 1014 case ROTATESUFFIX: 1015 strlcpy(rotatesuffix, yylval.str, sizeof(rotatesuffix)); 1016 DBGL(DL_RCCF, (logit(LL_DBG, "system: rotatesuffix = %s", yylval.str))); 1017 break; 1018 1019 case RTPRIO: 1020#ifdef USE_RTPRIO 1021 rt_prio = yylval.num; 1022 if (rt_prio < RTP_PRIO_MIN || rt_prio > RTP_PRIO_MAX) 1023 { 1024 config_error_flag++; 1025 logit(LL_ERR, "system: error, rtprio (%d) out of range!", yylval.num); 1026 } 1027 else 1028 { 1029 DBGL(DL_RCCF, (logit(LL_DBG, "system: rtprio = %d", yylval.num))); 1030 } 1031#else 1032 rt_prio = RTPRIO_NOTUSED; 1033#endif 1034 break; 1035 1036 case TINAINITPROG: 1037 strlcpy(tinainitprog, yylval.str, sizeof(tinainitprog)); 1038 DBGL(DL_RCCF, (logit(LL_DBG, "system: tinainitprog = %s", yylval.str))); 1039 break; 1040 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; 1045 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 1059 { 1060 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"unitlengthsrc\" at line %d!", lineno); 1061 config_error_flag++; 1062 } 1063 break; 1064 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) 1070 { 1071 logit(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"usrdevicename\" at line %d!", lineno); 1072 config_error_flag++; 1073 } 1074 break; 1075 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; 1080 1081 case USEACCTFILE: 1082 useacctfile = yylval.booln; 1083 DBGL(DL_RCCF, (logit(LL_DBG, "system: useacctfile = %d", yylval.booln))); 1084 break; 1085 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; 1090 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; 1095 1096 default: 1097 logit(LL_ERR, "ERROR parsing config file: unknown keyword at line %d!", lineno); 1098 config_error_flag++; 1099 break; 1100 } 1101} 1102 1103/*---------------------------------------------------------------------------* 1104 * parse a date/time range 1105 *---------------------------------------------------------------------------*/ 1106static void 1107parse_valid(char *dt) 1108{ 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 1119 */ 1120 1121 int day = 0; 1122 int fromhr = 0; 1123 int frommin = 0; 1124 int tohr = 0; 1125 int tomin = 0; 1126 int ret; 1127 1128 for (;;) 1129 { 1130 if ( ( ((*dt >= '0') && (*dt <= '9')) && (*(dt+1) == ':') ) || 1131 ( ((*dt >= '0') && (*dt <= '2')) && ((*(dt+1) >= '0') && (*(dt+1) <= '9')) && (*(dt+2) == ':') ) ) 1132 { 1133 /* dt points to time spec */ 1134 ret = sscanf(dt, "%d:%d-%d:%d", &fromhr, &frommin, &tohr, &tomin); 1135 if (ret !=4) 1136 { 1137 logit(LL_ERR, "ERROR parsing config file: timespec [%s] error at line %d!", *dt, lineno); 1138 config_error_flag++; 1139 return; 1140 } 1141 1142 if (fromhr < 0 || fromhr > 24 || tohr < 0 || tohr > 24 || 1143 frommin < 0 || frommin > 59 || tomin < 0 || tomin > 59) 1144 { 1145 logit(LL_ERR, "ERROR parsing config file: invalid time [%s] at line %d!", *dt, lineno); 1146 config_error_flag++; 1147 return; 1148 } 1149 break; 1150 } 1151 else if ((*dt >= '0') && (*dt <= '7')) 1152 { 1153 /* dt points to day spec */ 1154 day |= 1 << (*dt - '0'); 1155 dt++; 1156 continue; 1157 } 1158 else if (*dt == ',') 1159 { 1160 /* dt points to delimiter */ 1161 dt++; 1162 continue; 1163 } 1164 else if (*dt == '\0') 1165 { 1166 /* dt points to end of string */ 1167 break; 1168 } 1169 else 1170 { 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; 1175 } 1176 } 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; 1182} 1183 1184void 1185flush_config() 1186{ 1187 if (current_cfe != NULL) { 1188 add_cfg_entry(current_cfe); 1189 } 1190} 1191 1192/*---------------------------------------------------------------------------* 1193 * configuration validation and consistency check 1194 *---------------------------------------------------------------------------*/ 1195static void 1196check_config(void) 1197{ 1198 struct cfg_entry *cep = NULL; 1199 int i; 1200 int error = 0; 1201 1202 /* regular expression table */ 1203 1204 for (i=0; i < MAX_RE; i++) 1205 { 1206 if ((rarr[i].re_expr != NULL) && (rarr[i].re_prog == NULL)) 1207 { 1208 logit(LL_ERR, "check_config: regular expression %d without program!", i); 1209 error++; 1210 } 1211 if ((rarr[i].re_prog != NULL) && (rarr[i].re_expr == NULL)) 1212 { 1213 logit(LL_ERR, "check_config: regular expression program %d without expression!", i); 1214 error++; 1215 } 1216 } 1217 1218 /* entry sections */ 1219 1220 for (cep = get_first_cfg_entry(); cep; cep = NEXT_CFE(cep)) { 1221 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++; 1227 } 1228 if (cep->usrdeviceunit < 0) { 1229 logit(LL_ERR, "check_config: usrdeviceunit not set in entry \"%s\"!", 1230 cep->name); 1231 error++; 1232 } 1233 1234 /* numbers used for dialout */ 1235 1236 if ((cep->inout != DIR_INONLY) && (cep->dialin_reaction != REACT_ANSWER)) 1237 { 1238 if (cep->remote_numbers_count == 0) 1239 { 1240 logit(LL_ERR, "check_config: remote-phone-dialout not set in entry \"%s\"!", 1241 cep->name); 1242 error++; 1243 } 1244 } 1245 1246 /* numbers used for incoming calls */ 1247 1248 if (cep->inout != DIR_OUTONLY) 1249 { 1250 if (strlen(cep->local_phone_incoming) == 0) 1251 { 1252 logit(LL_ERR, "check_config: local-phone-incoming not set in entry \"%s\"!", 1253 cep->name); 1254 error++; 1255 } 1256 if (cep->incoming_numbers_count == 0) 1257 { 1258 logit(LL_ERR, "check_config: remote-phone-incoming not set in entry \"%s\"!", 1259 cep->name); 1260 error++; 1261 } 1262 } 1263 1264 if ((cep->dialin_reaction == REACT_ANSWER) && (cep->b1protocol != BPROT_NONE)) 1265 { 1266 logit(LL_ERR, "check_config: b1protocol not raw for telephony in entry \"%s\"!", 1267 cep->name); 1268 error++; 1269 } 1270 1271 if ((cep->ppp_send_auth == AUTH_PAP) || (cep->ppp_send_auth == AUTH_CHAP)) 1272 { 1273 if (cep->ppp_send_name == NULL) 1274 { 1275 logit(LL_ERR, "check_config: no remote authentification name in entry \"%s\"!", 1276 cep->name); 1277 error++; 1278 } 1279 if (cep->ppp_send_password == NULL) 1280 { 1281 logit(LL_ERR, "check_config: no remote authentification password in entry \"%s\"!", 1282 cep->name); 1283 error++; 1284 } 1285 } 1286 if ((cep->ppp_expect_auth == AUTH_PAP) || (cep->ppp_expect_auth == AUTH_CHAP)) 1287 { 1288 if (cep->ppp_expect_name == NULL) 1289 { 1290 logit(LL_ERR, "check_config: no local authentification name in entry \"%s\"!", 1291 cep->name); 1292 error++; 1293 } 1294 if (cep->ppp_expect_password == NULL) 1295 { 1296 logit(LL_ERR, "check_config: no local authentification secret in entry \"%s\"!", 1297 cep->name); 1298 error++; 1299 } 1300 } 1301 1302 if (cep->ppp_expect_auth != AUTH_UNDEF 1303 || cep->ppp_send_auth != AUTH_UNDEF) 1304 set_isppp_auth(cep); 1305 1306 /* 1307 * Only if AUTOUPDOWN_YES is the only bit set, otherwise 1308 * we already have handled this interface. 1309 */ 1310 if (cep->autoupdown == AUTOUPDOWN_YES) 1311 set_autoupdown(cep); 1312 } 1313 if (error) { 1314 logit(LL_ERR, "check_config: %d error(s) in configuration file, exiting!", 1315 error); 1316 do_exit(1); 1317 } 1318} 1319 1320/*---------------------------------------------------------------------------* 1321 * print the configuration 1322 *---------------------------------------------------------------------------*/ 1323static void 1324print_config(void) 1325{ 1326#define PFILE stdout 1327 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]; 1336 1337 time(&now); 1338 strlcpy(mytime, ctime(&now), sizeof(mytime)); 1339 mytime[strlen(mytime)-1] = '\0'; 1340 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); 1349 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 1356 1357 /* regular expression table */ 1358 1359 for (i=0; i < MAX_RE; i++) 1360 { 1361 if (rarr[i].re_expr != NULL) 1362 { 1363 fprintf(PFILE, "regexpr = \"%s\"\t\t# scan logfile for this expression\n", rarr[i].re_expr); 1364 } 1365 if (rarr[i].re_prog != NULL) 1366 { 1367 fprintf(PFILE, "regprog = %s\t\t# program to run when expression is matched\n", rarr[i].re_prog); 1368 } 1369 } 1370 1371#ifdef I4B_EXTERNAL_MONITOR 1372 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); 1375 1376 m_rights = monitor_next_rights(NULL); 1377 if (m_rights != NULL) 1378 { 1379 const char *s = "error\n"; 1380 char b[512]; 1381 1382 for ( ; m_rights != NULL; m_rights = monitor_next_rights(m_rights)) 1383 { 1384 if (m_rights->local) 1385 { 1386 fprintf(PFILE, "monitor = \"%s\"\t\t# local socket name for monitoring\n", m_rights->name); 1387 } 1388 else 1389 { 1390 struct in_addr ia; 1391 ia.s_addr = ntohl(m_rights->net); 1392 1393 switch (m_rights->mask) 1394 { 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; 1494 } 1495 fprintf(PFILE, "monitor = \"%s/%s\"\t\t# host (net/mask) allowed to connect for monitoring\n", inet_ntoa(ia), s); 1496 } 1497 b[0] = '\0'; 1498 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)); 1511 1512 if (strlen(b) > 0 && b[strlen(b)-1] == ',') 1513 b[strlen(b)-1] = '\0'; 1514 1515 fprintf(PFILE, "monitor-access = %s\t\t# monitor access rights\n", b); 1516 } 1517 } 1518 1519#endif 1520 /* entry sections */ 1521 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"); 1528 1529 fprintf(PFILE, "name = %s\t\t# name for this entry section\n", cep->name); 1530 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) 1534 { 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; 1541 } 1542 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); 1545 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"); 1547 1548 fprintf(PFILE, "direction = "); 1549 switch (cep->inout) 1550 { 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; 1560 } 1561 1562 if (cep->remote_numbers_count > 1) 1563 { 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); 1566 1567 fprintf(PFILE, "remdial-handling = "); 1568 1569 switch (cep->remote_numbers_handling) 1570 { 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; 1580 } 1581 } 1582 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"); 1587 } 1588 1589 if (!(cep->inout == DIR_OUTONLY)) 1590 { 1591 int n; 1592 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); 1597 1598 fprintf(PFILE, "dialin-reaction = "); 1599 switch (cep->dialin_reaction) 1600 { 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; 1616 } 1617 } 1618 1619 { 1620 const char *s; 1621 switch (cep->ppp_expect_auth) 1622 { 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; 1635 } 1636 if (s != NULL) 1637 { 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) 1640 { 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"); 1644 } 1645 } 1646 switch (cep->ppp_send_auth) 1647 { 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; 1660 } 1661 if (s != NULL) 1662 { 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) 1665 { 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); 1668 } 1669 } 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"); 1673 } 1674 } 1675 1676 if (cep->autoupdown == AUTOUPDOWN_NO) 1677 fprintf(PFILE, "autoupdown = no\n"); 1678 1679 { 1680 const char *s; 1681 fprintf(PFILE, "idletime-outgoing = %d\t\t# outgoing call idle timeout\n", cep->idle_time_out); 1682 1683 switch ( cep->shorthold_algorithm ) 1684 { 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; 1694 } 1695 1696 fprintf(PFILE, "idle-algorithm-outgoing = %s\t\t# outgoing call idle algorithm\n", s); 1697 } 1698 1699 if (!(cep->inout == DIR_OUTONLY)) 1700 fprintf(PFILE, "idletime-incoming = %d\t\t# incoming call idle timeout\n", cep->idle_time_in); 1701 1702 { 1703 fprintf(PFILE, "unitlengthsrc = "); 1704 switch (cep->unitlengthsrc) 1705 { 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; 1724 } 1725 1726 fprintf(PFILE, "earlyhangup = %d\t\t# early hangup safety time\n", cep->earlyhangup); 1727 1728 } 1729 1730 { 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); 1733 } 1734 1735 { 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); 1738 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); 1741 1742 if (!(cep->inout == DIR_INONLY)) 1743 { 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"); 1747 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) 1750 { 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); 1753 } 1754 } 1755 } 1756 fprintf(PFILE, "\n"); 1757} 1758 1759static int 1760lookup_l4_driver(const char *name) 1761{ 1762 msg_l4driver_lookup_t query; 1763 int e; 1764 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; 1770} 1771 1772