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 - misc support routines 28 * ---------------------------------- 29 * 30 * $Id: support.c,v 1.15 2009/04/16 05:56:32 lukem Exp $ 31 * 32 * $FreeBSD$ 33 * 34 * last edit-date: [Wed Oct 4 18:24:27 2000] 35 * 36 *---------------------------------------------------------------------------*/ 37 38#include "isdnd.h" 39 40static int isvalidtime(struct cfg_entry *cep); 41 42static SLIST_HEAD(, isdn_ctrl_state) isdn_ctrl_list = 43 SLIST_HEAD_INITIALIZER(isdn_ctrl_list); 44 45static SIMPLEQ_HEAD(, cfg_entry) cfg_entry_list = 46 SIMPLEQ_HEAD_INITIALIZER(cfg_entry_list); 47 48/*---------------------------------------------------------------------------* 49 * find an active entry by driver type and driver unit 50 *---------------------------------------------------------------------------*/ 51struct cfg_entry * 52find_active_entry_by_driver(int drivertype, int driverunit) 53{ 54 struct cfg_entry *cep = NULL; 55 56 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) { 57 58 if (!((cep->usrdevice == drivertype) && 59 (cep->usrdeviceunit == driverunit))) 60 { 61 continue; 62 } 63 64 /* check time interval */ 65 66 if (isvalidtime(cep) == 0) 67 { 68 DBGL(DL_MSG, (logit(LL_DBG, "find_active_entry_by_driver: entry %d, time not valid!", cep->index))); 69 continue; 70 } 71 72 /* found */ 73 74 if (cep->cdid == CDID_UNUSED) 75 { 76 DBGL(DL_MSG, (logit(LL_DBG, "find_active_entry_by_driver: entry %d [%s%d], cdid=CDID_UNUSED !", 77 cep->index, cep->usrdevicename, driverunit))); 78 return(NULL); 79 } 80 else if (cep->cdid == CDID_RESERVED) 81 { 82 DBGL(DL_MSG, (logit(LL_DBG, "find_active_entry_by_driver: entry %d [%s%d], cdid=CDID_RESERVED!", 83 cep->index, cep->usrdevicename, driverunit))); 84 return(NULL); 85 } 86 return(cep); 87 } 88 return(NULL); 89} 90 91/*---------------------------------------------------------------------------* 92 * find entry by drivertype and driverunit and setup for dialing out 93 *---------------------------------------------------------------------------*/ 94struct cfg_entry * 95find_by_device_for_dialout(int drivertype, int driverunit) 96{ 97 struct cfg_entry *cep; 98 99 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) { 100 101 /* compare driver type and unit */ 102 103 if (!((cep->usrdevice == drivertype) && 104 (cep->usrdeviceunit == driverunit))) 105 { 106 continue; 107 } 108 109 /* check time interval */ 110 111 if (isvalidtime(cep) == 0) 112 { 113 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: entry %d, time not valid!", cep->index))); 114 continue; 115 } 116 117 /* found, check if already reserved */ 118 119 if (cep->cdid == CDID_RESERVED) 120 { 121 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: entry %d, cdid reserved!", cep->index))); 122 return(NULL); 123 } 124 125 /* check if this entry is already in use ? */ 126 127 if (cep->cdid != CDID_UNUSED) 128 { 129 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: entry %d, cdid in use", cep->index))); 130 return(NULL); 131 } 132 133 if ((setup_dialout(cep)) == GOOD) 134 { 135 /* found an entry to be used for calling out */ 136 137 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: found entry %d!", cep->index))); 138 return(cep); 139 } 140 else 141 { 142 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: entry %d, setup_dialout() failed!", cep->index))); 143 return(NULL); 144 } 145 } 146 147 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: no entry found!"))); 148 return(NULL); 149} 150 151/*---------------------------------------------------------------------------* 152 * find entry by drivertype and driverunit and setup for dialing out 153 *---------------------------------------------------------------------------*/ 154struct cfg_entry * 155find_by_device_for_dialoutnumber(int drivertype, int driverunit, int cmdlen, char *cmd) 156{ 157 struct cfg_entry *cep; 158 int j; 159 160 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) { 161 162 /* compare driver type and unit */ 163 164 if (!((cep->usrdevice == drivertype) && 165 (cep->usrdeviceunit == driverunit))) 166 { 167 continue; 168 } 169 170 /* check time interval */ 171 172 if (isvalidtime(cep) == 0) 173 { 174 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, time not valid!", cep->index))); 175 continue; 176 } 177 178 /* found, check if already reserved */ 179 180 if (cep->cdid == CDID_RESERVED) 181 { 182 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, cdid reserved!", cep->index))); 183 return(NULL); 184 } 185 186 /* check if this entry is already in use ? */ 187 188 if (cep->cdid != CDID_UNUSED) 189 { 190 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, cdid in use", cep->index))); 191 return(NULL); 192 } 193 194 /* check number and copy to cep->remote_numbers[] */ 195 196 for (j = 0; j < cmdlen; j++) 197 { 198 if (!(isdigit((unsigned char)*(cmd+j)))) 199 { 200 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, dial string contains non-digit at pos %d", cep->index, j))); 201 return(NULL); 202 } 203 /* fill in number to dial */ 204 cep->remote_numbers[0].number[j] = *(cmd+j); 205 } 206 cep->remote_numbers[0].number[j] = '\0'; 207 cep->remote_numbers_count = 1; 208 209 if ((setup_dialout(cep)) == GOOD) 210 { 211 /* found an entry to be used for calling out */ 212 213 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: found entry %d!", cep->index))); 214 return(cep); 215 } 216 else 217 { 218 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, setup_dialout() failed!", cep->index))); 219 return(NULL); 220 } 221 } 222 223 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: no entry found!"))); 224 return(NULL); 225} 226 227/*---------------------------------------------------------------------------* 228 * find entry by drivertype and driverunit and setup for dialing out 229 *---------------------------------------------------------------------------*/ 230int 231setup_dialout(struct cfg_entry *cep) 232{ 233 struct isdn_ctrl_state *ctrl; 234 int i; 235 236 if (cep->isdncontroller < 0) { 237 /* we are free to choose a controller */ 238 for (ctrl = get_first_ctrl_state(); ctrl; ctrl = NEXT_CTRL(ctrl)) { 239 if (get_controller_state(ctrl) != CTRL_UP) 240 continue; 241 switch (cep->isdnchannel) { 242 case CHAN_ANY: 243 for (i = 0; i < ctrl->nbch; i++) 244 { 245 if (ret_channel_state(ctrl, i) 246 == CHAN_IDLE) 247 break; 248 } 249 if (i == ctrl->nbch) 250 continue; 251 break; 252 default: 253 if (ret_channel_state(ctrl, cep->isdnchannel) 254 != CHAN_IDLE) 255 continue; 256 break; 257 } 258 /* this controller looks ok */ 259 break; 260 } 261 } else { 262 /* fixed controller in config, use that */ 263 ctrl = find_ctrl_state(cep->isdncontroller); 264 } 265 266 if (ctrl == NULL) 267 return (ERROR); 268 269 /* check controller operational */ 270 271 if (get_controller_state(ctrl) != CTRL_UP) 272 { 273 DBGL(DL_MSG, (logit(LL_DBG, "setup_dialout: entry %s, controller is down", cep->name))); 274 return(ERROR); 275 } 276 277 cep->isdncontrollerused = ctrl->isdnif; 278 279 /* check channel available */ 280 281 switch (cep->isdnchannel) 282 { 283 case CHAN_ANY: 284 for (i = 0; i < ctrl->nbch; i++) 285 { 286 if (ret_channel_state(ctrl, i) == CHAN_IDLE) 287 break; 288 } 289 if (i == ctrl->nbch) 290 { 291 DBGL(DL_MSG, (logit(LL_DBG, "setup_dialout: entry %s, no channel free", cep->name))); 292 return(ERROR); 293 } 294 cep->isdnchannelused = CHAN_ANY; 295 break; 296 297 default: 298 if (ret_channel_state(ctrl, cep->isdnchannel) != CHAN_IDLE) 299 { 300 DBGL(DL_MSG, (logit(LL_DBG, "setup_dialout: entry %s, channel not free", cep->name))); 301 return(ERROR); 302 } 303 cep->isdnchannelused = cep->isdnchannel; 304 break; 305 } 306 307 DBGL(DL_MSG, (logit(LL_DBG, "setup_dialout: entry %s ok!", cep->name))); 308 309 /* preset disconnect cause */ 310 311 SET_CAUSE_TYPE(cep->disc_cause, CAUSET_I4B); 312 SET_CAUSE_VAL(cep->disc_cause, CAUSE_I4B_NORMAL); 313 314 return(GOOD); 315} 316 317/*---------------------------------------------------------------------------* 318 * find entry by drivertype and driverunit 319 *---------------------------------------------------------------------------*/ 320struct cfg_entry * 321get_cep_by_driver(int drivertype, int driverunit) 322{ 323 struct cfg_entry *cep; 324 325 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) { 326 327 if (!((cep->usrdevice == drivertype) && 328 (cep->usrdeviceunit == driverunit))) 329 { 330 continue; 331 } 332 333 /* check time interval */ 334 335 if (isvalidtime(cep) == 0) 336 { 337 DBGL(DL_MSG, (logit(LL_DBG, "get_cep_by_driver: entry %d, time not valid!", cep->index))); 338 continue; 339 } 340 341 DBGL(DL_MSG, (logit(LL_DBG, "get_cep_by_driver: found entry %d!", cep->index))); 342 return(cep); 343 } 344 return(NULL); 345} 346 347/*---------------------------------------------------------------------------* 348 * find a matching entry for an incoming call 349 * 350 * - not found/no match: log output with LL_CHD and return NULL 351 * - found/match: make entry in free cep, return address 352 *---------------------------------------------------------------------------*/ 353struct cfg_entry * 354find_matching_entry_incoming(msg_connect_ind_t *mp, int len) 355{ 356 struct cfg_entry *cep = NULL; 357 static const char resvd_type[] = "reserverd"; 358 static const char no_type[] = "no type"; 359 static const char * const numbering_types[] = { 360 "unknown", 361 "international", 362 "national", 363 "network specific", 364 "subscriber", 365 "abbreviated", 366 resvd_type, 367 resvd_type, 368 resvd_type 369 }; 370 const char * ntype; 371 int i; 372 373 /* older kernels do not deliver all the information */ 374 if (((u_int8_t*)&mp->type_plan - (u_int8_t*)mp + (int)sizeof(mp->type_plan)) <= len) { 375 ntype = numbering_types[(mp->type_plan & 0x70)>>4]; 376 } else { 377 ntype = no_type; 378 } 379 380 /* check for CW (call waiting) early */ 381 382 if (mp->channel == CHAN_NO) 383 { 384 if (aliasing) 385 { 386 const char *src_tela = "ERROR-src_tela"; 387 const char *dst_tela = "ERROR-dst_tela"; 388 389 src_tela = get_alias(mp->src_telno); 390 dst_tela = get_alias(mp->dst_telno); 391 392 logit(LL_CHD, "%05d <unknown> CW from %s (%s) to %s (%s) (no channel free)", 393 mp->header.cdid, src_tela, ntype, dst_tela, mp->display); 394 } 395 else 396 { 397 logit(LL_CHD, "%05d <unknown> call waiting from %s (%s) to %s (%s) (no channel free)", 398 mp->header.cdid, mp->src_telno, ntype, mp->dst_telno, mp->display); 399 } 400 return(NULL); 401 } 402 403 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) { 404 405 int n; 406 struct isdn_ctrl_state *ctrl; 407 408 /* check my number */ 409 410 if (strncmp(cep->local_phone_incoming, mp->dst_telno, strlen(cep->local_phone_incoming))) 411 { 412 DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, myno %s != incomingno %s", 413 cep->index, cep->local_phone_incoming, mp->dst_telno))); 414 continue; 415 } 416 417 /* check all allowed remote number's for this entry */ 418 419 for (n = 0; n < cep->incoming_numbers_count; n++) 420 { 421 incoming_number_t *in = &cep->remote_phone_incoming[n]; 422 if (in->number[0] == '*') 423 break; 424 if (strncmp(in->number, mp->src_telno, strlen(in->number))) 425 { 426 DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, remno %s != incomingfromno %s", 427 cep->index, in->number, mp->src_telno))); 428 } 429 else 430 break; 431 } 432 if (n >= cep->incoming_numbers_count) 433 continue; 434 435 /* check b protocol */ 436 437 if (cep->b1protocol != mp->bprot) 438 { 439 DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, bprot %d != incomingprot %d", 440 cep->index, cep->b1protocol, mp->bprot))); 441 continue; 442 } 443 444 /* is this entry currently in use ? */ 445 446 if (cep->cdid != CDID_UNUSED) 447 { 448 if (cep->cdid == CDID_RESERVED) 449 { 450 DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, cdid is reserved", cep->index))); 451 } 452 else if (cep->dialin_reaction == REACT_ACCEPT 453 && cep->dialouttype == DIALOUT_CALLEDBACK) 454 { 455 /* 456 * We might consider doing this even if this is 457 * not a calledback config entry - BUT: there are 458 * severe race conditions and timinig problems 459 * ex. if both sides run I4B with no callback 460 * delay - both may shutdown the outgoing call 461 * and never be able to establish a connection. 462 * In the called-back case this should not happen. 463 */ 464 DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, incoming call for callback in progress (cdid %05d)", cep->index, cep->cdid))); 465 466 /* save the current call state, we're going to overwrite it with the 467 * new incoming state below... */ 468 cep->saved_call.cdid = cep->cdid; 469 cep->saved_call.controller = cep->isdncontrollerused; 470 cep->saved_call.channel = cep->isdnchannelused; 471 } 472 else 473 { 474 DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, cdid in use", cep->index))); 475 continue; /* yes, next */ 476 } 477 } 478 479 /* check controller value ok */ 480 ctrl = find_ctrl_state(mp->controller); 481 482 if (ctrl == NULL) 483 { 484 logit(LL_CHD, "%05d %s incoming call with invalid controller %d", 485 mp->header.cdid, cep->name, mp->controller); 486 return(NULL); 487 } 488 489 /* check controller marked up */ 490 491 if (get_controller_state(ctrl) != CTRL_UP) 492 { 493 logit(LL_CHD, "%05d %s incoming call, controller %d DOWN!", 494 mp->header.cdid, cep->name, mp->controller); 495 return(NULL); 496 } 497 498 /* check channel he wants */ 499 500 switch (mp->channel) 501 { 502 case CHAN_ANY: 503 for (i = 0; i < ctrl->nbch; i++) 504 if (ret_channel_state(ctrl, i) == CHAN_IDLE) 505 break; 506 if (i == ctrl->nbch) 507 { 508 logit(LL_CHD, "%05d %s incoming call, no channel free!", 509 mp->header.cdid, cep->name); 510 return(NULL); 511 } 512 break; 513 514 case CHAN_NO: 515 logit(LL_CHD, "%05d %s incoming call, call waiting (no channel available)!", 516 mp->header.cdid, cep->name); 517 return(NULL); 518 break; 519 520 default: 521 if ((ret_channel_state(ctrl, mp->channel)) != CHAN_IDLE) 522 { 523 logit(LL_CHD, "%05d %s incoming call, channel B%d not free!", 524 mp->header.cdid, cep->name, mp->channel); 525 return(NULL); 526 } 527 break; 528 } 529 530 /* check time interval */ 531 532 if (isvalidtime(cep) == 0) 533 { 534 DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, time not valid!", cep->index))); 535 continue; 536 } 537 538 /* found a matching entry */ 539 540 cep->cdid = mp->header.cdid; 541 cep->isdncontrollerused = mp->controller; 542 cep->isdnchannelused = mp->channel; 543/*XXX*/ cep->disc_cause = 0; 544 545 /* cp number to real one used */ 546 547 strlcpy(cep->real_phone_incoming, mp->src_telno, 548 sizeof(cep->real_phone_incoming)); 549 550 /* copy display string */ 551 552 strlcpy(cep->display, mp->display, sizeof(cep->display)); 553 554 /* entry currently down ? */ 555 556 if (cep->state == ST_DOWN) 557 { 558 msg_updown_ind_t mui; 559 560 /* set interface up */ 561 562 DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, ", cep->index))); 563 564 mui.driver = cep->usrdevice; 565 mui.driver_unit = cep->usrdeviceunit; 566 mui.updown = SOFT_ENA; 567 568 if ((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0) 569 { 570 logit(LL_ERR, "find_matching_entry_incoming: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno)); 571 error_exit(1, "find_matching_entry_incoming: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno)); 572 } 573 574 cep->down_retry_count = 0; 575 cep->state = ST_IDLE; 576 } 577 return(cep); 578 } 579 580 if (aliasing) 581 { 582 const char *src_tela = "ERROR-src_tela"; 583 const char *dst_tela = "ERROR-dst_tela"; 584 585 src_tela = get_alias(mp->src_telno); 586 dst_tela = get_alias(mp->dst_telno); 587 588 logit(LL_CHD, "%05d Call from %s (%s) to %s (%s)", 589 mp->header.cdid, src_tela, ntype, dst_tela, mp->display); 590 } 591 else 592 { 593 logit(LL_CHD, "%05d <unknown> incoming call from %s (%s) to %s (%s)", 594 mp->header.cdid, mp->src_telno, ntype, mp->dst_telno, mp->display); 595 } 596 return(NULL); 597} 598 599/*---------------------------------------------------------------------------* 600 * return address of ACTIVE config entry by controller and channel 601 *---------------------------------------------------------------------------*/ 602struct cfg_entry * 603get_cep_by_cc(int ctrlr, int chan) 604{ 605 struct cfg_entry *cep; 606 struct isdn_ctrl_state *cts; 607 608 cts = find_ctrl_state(ctrlr); 609 if (cts == NULL) 610 return(NULL); 611 612 if (chan < 0 || chan >= cts->nbch) 613 return(NULL); 614 615 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) { 616 617 if ((cep->cdid != CDID_UNUSED) && 618 (cep->cdid != CDID_RESERVED) && 619 (cep->isdnchannelused == chan) && 620 (cep->isdncontrollerused == ctrlr) && 621 ((ret_channel_state(cts, chan)) == CHAN_RUN)) 622 { 623 return (cep); 624 } 625 } 626 return(NULL); 627} 628 629/*---------------------------------------------------------------------------* 630 * return address of config entry identified by cdid 631 *---------------------------------------------------------------------------*/ 632struct cfg_entry * 633get_cep_by_cdid(int cdid) 634{ 635 struct cfg_entry *cep; 636 637 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) { 638 if (cep->cdid == cdid || cep->saved_call.cdid == cdid) 639 return(cep); 640 } 641 return(NULL); 642} 643 644/*---------------------------------------------------------------------------* 645 * process AOCD charging messages 646 *---------------------------------------------------------------------------*/ 647void 648handle_charge(struct cfg_entry *cep) 649{ 650 time_t now = time(NULL); 651 652 if (cep->aoc_last == 0) /* no last timestamp yet ? */ 653 { 654 cep->aoc_last = now; /* add time stamp */ 655 } 656 else if (cep->aoc_now == 0) /* no current timestamp yet ? */ 657 { 658 cep->aoc_now = now; /* current timestamp */ 659 } 660 else 661 { 662 cep->aoc_last = cep->aoc_now; 663 cep->aoc_now = now; 664 cep->aoc_diff = cep->aoc_now - cep->aoc_last; 665 cep->aoc_valid = AOC_VALID; 666 } 667 668#ifdef USE_CURSES 669 if (do_fullscreen) 670 display_charge(cep); 671#endif 672 673#ifdef I4B_EXTERNAL_MONITOR 674 if (do_monitor && accepted) 675 monitor_evnt_charge(cep, cep->charge, 0); 676#endif 677 678 if (cep->aoc_valid == AOC_VALID) 679 { 680 if (cep->aoc_diff != cep->unitlength) 681 { 682 DBGL(DL_MSG, (logit(LL_DBG, "handle_charge: AOCD unit length updated %d -> %d secs", cep->unitlength, cep->aoc_diff))); 683 684 cep->unitlength = cep->aoc_diff; 685 686 unitlen_chkupd(cep); 687 } 688 else 689 { 690#ifdef NOTDEF 691 DBGL(DL_MSG, (logit(LL_DBG, "handle_charge: AOCD unit length still %d secs", cep->unitlength))); 692#endif 693 } 694 } 695} 696 697/*---------------------------------------------------------------------------* 698 * update kernel idle_time, earlyhup_time and unitlen_time 699 *---------------------------------------------------------------------------*/ 700void 701unitlen_chkupd(struct cfg_entry *cep) 702{ 703 msg_timeout_upd_t tupd; 704 705 tupd.cdid = cep->cdid; 706 707 /* init the short hold data based on the shorthold algorithm type */ 708 709 switch (cep->shorthold_algorithm) 710 { 711 case SHA_FIXU: 712 tupd.shorthold_data.shorthold_algorithm = SHA_FIXU; 713 tupd.shorthold_data.unitlen_time = cep->unitlength; 714 tupd.shorthold_data.idle_time = cep->idle_time_out; 715 tupd.shorthold_data.earlyhup_time = cep->earlyhangup; 716 break; 717 718 case SHA_VARU: 719 tupd.shorthold_data.shorthold_algorithm = SHA_VARU; 720 tupd.shorthold_data.unitlen_time = cep->unitlength; 721 tupd.shorthold_data.idle_time = cep->idle_time_out; 722 tupd.shorthold_data.earlyhup_time = 0; 723 break; 724 default: 725 logit(LL_ERR, "unitlen_chkupd bad shorthold_algorithm %d", cep->shorthold_algorithm ); 726 return; 727 break; 728 } 729 730 if ((ioctl(isdnfd, I4B_TIMEOUT_UPD, &tupd)) < 0) 731 { 732 logit(LL_ERR, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno)); 733 error_exit(1, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno)); 734 } 735} 736 737/*--------------------------------------------------------------------------* 738 * this is intended to be called by do_exit and closes down all 739 * active connections before the daemon exits or is reconfigured. 740 *--------------------------------------------------------------------------*/ 741void 742close_allactive(void) 743{ 744 int i, j; 745 struct cfg_entry *cep = NULL; 746 struct isdn_ctrl_state *cst; 747 748 j = 0; 749 750 SLIST_FOREACH(cst, &isdn_ctrl_list, ctrlq) { 751 752 if ((get_controller_state(cst)) != CTRL_UP) 753 continue; 754 755 for (i = 0; i < cst->nbch; i++) 756 { 757 if ((ret_channel_state(cst, i)) == CHAN_RUN) 758 { 759 if ((cep = get_cep_by_cc(cst->isdnif, i)) 760 != NULL) 761 { 762#ifdef USE_CURSES 763 if (do_fullscreen) 764 display_disconnect(cep); 765#endif 766#ifdef I4B_EXTERNAL_MONITOR 767 monitor_evnt_disconnect(cep); 768#endif 769 next_state(cep, EV_DRQ); 770 j++; 771 } 772 } 773 } 774 } 775 776 if (j) 777 { 778 logit(LL_DMN, "close_allactive: waiting for all connections terminated"); 779 sleep(5); 780 } 781 782 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) { 783 if (cep->autoupdown & AUTOUPDOWN_DONE) { 784 struct ifreq ifr; 785 int r, s; 786 787 s = socket(AF_INET, SOCK_DGRAM, 0); 788 memset(&ifr, 0, sizeof ifr); 789 snprintf(ifr.ifr_name, sizeof ifr.ifr_name, "%s%d", cep->usrdevicename, cep->usrdeviceunit); 790 r = ioctl(s, SIOCGIFFLAGS, &ifr); 791 if (r >= 0) { 792 ifr.ifr_flags &= ~IFF_UP; 793 ioctl(s, SIOCSIFFLAGS, &ifr); 794 } 795 close(s); 796 cep->autoupdown &= ~AUTOUPDOWN_DONE; 797 } 798 } 799 800} 801 802/*--------------------------------------------------------------------------* 803 * set an interface up 804 *--------------------------------------------------------------------------*/ 805void 806if_up(struct cfg_entry *cep) 807{ 808 msg_updown_ind_t mui; 809 810 /* set interface up */ 811 812 DBGL(DL_MSG, (logit(LL_DBG, "if_up: taking %s%d up", cep->usrdevicename, cep->usrdeviceunit))); 813 814 mui.driver = cep->usrdevice; 815 mui.driver_unit = cep->usrdeviceunit; 816 mui.updown = SOFT_ENA; 817 818 if ((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0) 819 { 820 logit(LL_ERR, "if_up: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno)); 821 error_exit(1, "if_up: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno)); 822 } 823 cep->down_retry_count = 0; 824 825#ifdef USE_CURSES 826 if (do_fullscreen) 827 display_updown(cep, 1); 828#endif 829#ifdef I4B_EXTERNAL_MONITOR 830 monitor_evnt_updown(cep, 1); 831#endif 832 833} 834 835/*--------------------------------------------------------------------------* 836 * set an interface down 837 *--------------------------------------------------------------------------*/ 838void 839if_down(struct cfg_entry *cep) 840{ 841 msg_updown_ind_t mui; 842 843 /* set interface up */ 844 845 DBGL(DL_MSG, (logit(LL_DBG, "if_down: taking %s%d down", cep->usrdevicename, cep->usrdeviceunit))); 846 847 mui.driver = cep->usrdevice; 848 mui.driver_unit = cep->usrdeviceunit; 849 mui.updown = SOFT_DIS; 850 851 if ((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0) 852 { 853 logit(LL_ERR, "if_down: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno)); 854 error_exit(1, "if_down: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno)); 855 } 856 cep->went_down_time = time(NULL); 857 cep->down_retry_count = 0; 858 859#ifdef USE_CURSES 860 if (do_fullscreen) 861 display_updown(cep, 0); 862#endif 863#ifdef I4B_EXTERNAL_MONITOR 864 monitor_evnt_updown(cep, 0); 865#endif 866 867} 868 869/*--------------------------------------------------------------------------* 870 * send a dial response to (an interface in) the kernel 871 *--------------------------------------------------------------------------*/ 872void 873dialresponse(struct cfg_entry *cep, int dstat) 874{ 875 msg_dialout_resp_t mdr; 876 877 static const char *stattab[] = { 878 "normal condition", 879 "temporary failure", 880 "permanent failure", 881 "dialout not allowed" 882 }; 883 884 if (dstat < DSTAT_NONE || dstat > DSTAT_INONLY) 885 { 886 logit(LL_ERR, "dialresponse: dstat out of range %d!", dstat); 887 return; 888 } 889 890 mdr.driver = cep->usrdevice; 891 mdr.driver_unit = cep->usrdeviceunit; 892 mdr.stat = dstat; 893 mdr.cause = cep->disc_cause; 894 895 if ((ioctl(isdnfd, I4B_DIALOUT_RESP, &mdr)) < 0) 896 { 897 logit(LL_ERR, "dialresponse: ioctl I4B_DIALOUT_RESP failed: %s", strerror(errno)); 898 error_exit(1, "dialresponse: ioctl I4B_DIALOUT_RESP failed: %s", strerror(errno)); 899 } 900 901 DBGL(DL_DRVR, (logit(LL_DBG, "dialresponse: sent [%s]", stattab[dstat]))); 902} 903 904/*--------------------------------------------------------------------------* 905 * screening/presentation indicator 906 *--------------------------------------------------------------------------*/ 907void 908handle_scrprs(int cdid, int scr, int prs, const char *caller) 909{ 910 /* screening indicator */ 911 912 if (scr < SCR_NONE || scr > SCR_NET) 913 { 914 logit(LL_ERR, "msg_connect_ind: invalid screening indicator value %d!", scr); 915 } 916 else 917 { 918 static const char *scrtab[] = { 919 "no screening indicator", 920 "sreening user provided, not screened", 921 "screening user provided, verified & passed", 922 "screening user provided, verified & failed", 923 "screening network provided", }; 924 925 if (extcallattr) 926 { 927 logit(LL_CHD, "%05d %s %s", cdid, caller, scrtab[scr]); 928 } 929 else 930 { 931 DBGL(DL_MSG, (logit(LL_DBG, "%s - %s", caller, scrtab[scr]))); 932 } 933 } 934 935 /* presentation indicator */ 936 937 if (prs < PRS_NONE || prs > PRS_RESERVED) 938 { 939 logit(LL_ERR, "msg_connect_ind: invalid presentation indicator value %d!", prs); 940 } 941 else 942 { 943 static const char *prstab[] = { 944 "no presentation indicator", 945 "presentation allowed", 946 "presentation restricted", 947 "number not available due to interworking", 948 "reserved presentation value" }; 949 950 if (extcallattr) 951 { 952 logit(LL_CHD, "%05d %s %s", cdid, caller, prstab[prs]); 953 } 954 else 955 { 956 DBGL(DL_MSG, (logit(LL_DBG, "%s - %s", caller, prstab[prs]))); 957 } 958 } 959} 960 961/*--------------------------------------------------------------------------* 962 * check if the time is valid for an entry 963 *--------------------------------------------------------------------------*/ 964static int 965isvalidtime(struct cfg_entry *cep) 966{ 967 time_t t; 968 struct tm *tp; 969 970 if (cep->day == 0) 971 return(1); 972 973 t = time(NULL); 974 tp = localtime(&t); 975 976 if (cep->day & HD) 977 { 978 if (isholiday(tp->tm_mday, (tp->tm_mon)+1, (tp->tm_year)+1900)) 979 { 980 DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: holiday %d.%d.%d", tp->tm_mday, (tp->tm_mon)+1, (tp->tm_year)+1900))); 981 goto dayok; 982 } 983 } 984 985 if (cep->day & (1 << tp->tm_wday)) 986 { 987 DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: day match"))); 988 goto dayok; 989 } 990 991 return(0); 992 993dayok: 994 if (cep->fromhr==0 && cep->frommin==0 && cep->tohr==0 && cep->tomin==0) 995 { 996 DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: no time specified, match!"))); 997 return(1); 998 } 999 1000 if (cep->tohr < cep->fromhr) 1001 { 1002 /* before 00:00 */ 1003 1004 if ( (tp->tm_hour > cep->fromhr) || 1005 (tp->tm_hour == cep->fromhr && tp->tm_min > cep->frommin) ) 1006 { 1007 DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: t<f-1, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!", 1008 cep->fromhr, cep->frommin, 1009 cep->tohr, cep->tomin, 1010 tp->tm_hour, tp->tm_min))); 1011 1012 return(1); 1013 } 1014 1015 /* after 00:00 */ 1016 1017 if ( (tp->tm_hour < cep->tohr) || 1018 (tp->tm_hour == cep->tohr && tp->tm_min < cep->tomin) ) 1019 { 1020 DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: t<f-2, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!", 1021 cep->fromhr, cep->frommin, 1022 cep->tohr, cep->tomin, 1023 tp->tm_hour, tp->tm_min))); 1024 1025 return(1); 1026 } 1027 } 1028 else if (cep->fromhr == cep->tohr) 1029 { 1030 if (tp->tm_min >= cep->frommin && tp->tm_min < cep->tomin) 1031 { 1032 DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: f=t, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!", 1033 cep->fromhr, cep->frommin, 1034 cep->tohr, cep->tomin, 1035 tp->tm_hour, tp->tm_min))); 1036 1037 return(1); 1038 } 1039 } 1040 else 1041 { 1042 if ((tp->tm_hour > cep->fromhr && tp->tm_hour < cep->tohr) || 1043 (tp->tm_hour == cep->fromhr && tp->tm_min >= cep->frommin) || 1044 (tp->tm_hour == cep->tohr && tp->tm_min < cep->tomin) ) 1045 { 1046 DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: t>f, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!", 1047 cep->fromhr, cep->frommin, 1048 cep->tohr, cep->tomin, 1049 tp->tm_hour, tp->tm_min))); 1050 return(1); 1051 } 1052 } 1053 DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, no match!", 1054 cep->fromhr, cep->frommin, 1055 cep->tohr, cep->tomin, 1056 tp->tm_hour, tp->tm_min))); 1057 1058 return(0); 1059} 1060 1061struct cfg_entry * 1062get_first_cfg_entry() 1063{ 1064 return (SIMPLEQ_FIRST(&cfg_entry_list)); 1065} 1066 1067int count_cfg_entries() 1068{ 1069 int cnt; 1070 struct cfg_entry *cfe; 1071 1072 cnt = 0; 1073 SIMPLEQ_FOREACH(cfe, &cfg_entry_list, cfgq) 1074 cnt++; 1075 1076 return (cnt); 1077} 1078 1079struct cfg_entry * 1080find_cfg_entry(int idx) 1081{ 1082 struct cfg_entry *cep; 1083 1084 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) 1085 if (cep->index == idx) 1086 return cep; 1087 return NULL; 1088} 1089 1090int 1091add_cfg_entry(struct cfg_entry *cfe) 1092{ 1093 struct cfg_entry *cep; 1094 int max = -1; 1095 1096 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) 1097 if (cep->index > max) 1098 max = cep->index; 1099 1100 cfe->index = max; 1101 SIMPLEQ_INSERT_TAIL(&cfg_entry_list, cfe, cfgq); 1102 return max; 1103} 1104 1105void 1106remove_all_cfg_entries() 1107{ 1108 struct cfg_entry *cep; 1109 1110 while (!SIMPLEQ_EMPTY(&cfg_entry_list)) { 1111 cep = SIMPLEQ_FIRST(&cfg_entry_list); 1112 SIMPLEQ_REMOVE_HEAD(&cfg_entry_list, cfgq); 1113 1114 if (cep->ppp_expect_name) 1115 free(cep->ppp_expect_name); 1116 if (cep->ppp_expect_password) 1117 free(cep->ppp_expect_password); 1118 if (cep->ppp_send_name) 1119 free(cep->ppp_send_name); 1120 if (cep->ppp_send_password) 1121 free(cep->ppp_send_password); 1122 1123 free(cep); 1124 } 1125} 1126 1127struct isdn_ctrl_state * get_first_ctrl_state() 1128{ 1129 return SLIST_FIRST(&isdn_ctrl_list); 1130} 1131 1132int count_ctrl_states() 1133{ 1134 int cnt = 0; 1135 struct isdn_ctrl_state *ctrl; 1136 1137 SLIST_FOREACH(ctrl, &isdn_ctrl_list, ctrlq) 1138 cnt++; 1139 1140 return (cnt); 1141} 1142 1143void remove_all_ctrl_state() 1144{ 1145 struct isdn_ctrl_state *ctrl; 1146 1147 while (!SLIST_EMPTY(&isdn_ctrl_list)) { 1148 ctrl = SLIST_FIRST(&isdn_ctrl_list); 1149 SLIST_REMOVE_HEAD(&isdn_ctrl_list, ctrlq); 1150 free(ctrl); 1151 } 1152} 1153 1154struct isdn_ctrl_state * 1155find_ctrl_state(int controller) 1156{ 1157 struct isdn_ctrl_state *ctrl; 1158 1159 SLIST_FOREACH(ctrl, &isdn_ctrl_list, ctrlq) 1160 if (ctrl->isdnif == controller) 1161 return ctrl; 1162 return NULL; 1163} 1164 1165int 1166add_ctrl_state(struct isdn_ctrl_state *cstate) 1167{ 1168 SLIST_INSERT_HEAD(&isdn_ctrl_list, cstate, ctrlq); 1169 return 0; 1170} 1171 1172int 1173remove_ctrl_state(int controller) 1174{ 1175 struct isdn_ctrl_state *ctrl = find_ctrl_state(controller); 1176 struct cfg_entry *cep; 1177 int i; 1178 1179 if (ctrl == NULL) 1180 return 0; 1181 1182 if ((get_controller_state(ctrl)) == CTRL_UP) { 1183 1184 for (i = 0; i < ctrl->nbch; i++) 1185 { 1186 if ((ret_channel_state(ctrl, i)) == CHAN_RUN) { 1187 if ((cep = get_cep_by_cc(controller, i)) 1188 != NULL) 1189 { 1190#ifdef USE_CURSES 1191 if (do_fullscreen) 1192 display_disconnect(cep); 1193#endif 1194#ifdef I4B_EXTERNAL_MONITOR 1195 monitor_evnt_disconnect(cep); 1196#endif 1197 cep->cdid = -1; 1198 cep->isdncontrollerused = -1; 1199 cep->isdnchannelused = -1; 1200 cep->state = ST_IDLE; 1201 } 1202 } 1203 } 1204 } 1205 1206 SLIST_REMOVE(&isdn_ctrl_list, ctrl, isdn_ctrl_state, ctrlq); 1207 return 0; 1208} 1209 1210/* EOF */ 1211