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 - message from kernel handling routines 28 * -------------------------------------------------- 29 * 30 * $Id: msghdl.c,v 1.11 2009/04/16 05:56:32 lukem Exp $ 31 * 32 * $FreeBSD$ 33 * 34 * last edit-date: [Thu Sep 21 11:11:48 2000] 35 * 36 *---------------------------------------------------------------------------*/ 37 38#include "isdnd.h" 39 40#include <sys/socket.h> 41#include <net/if.h> 42#include <net/if_types.h> 43 44#if defined(__FreeBSD__) 45#include <net/if_var.h> 46#endif 47 48#include <netinet/in.h> 49#include <netinet/in_systm.h> 50#include <netinet/in_var.h> 51#include <netinet/ip.h> 52#include <netinet/tcp.h> 53#include <netinet/udp.h> 54#include <netinet/ip_icmp.h> 55 56/*---------------------------------------------------------------------------* 57 * handle incoming CONNECT_IND (=SETUP) message 58 *---------------------------------------------------------------------------*/ 59void 60msg_connect_ind(msg_connect_ind_t *mp, int len) 61{ 62 struct cfg_entry *cep; 63 const char *src_tela = "ERROR-src_tela"; 64 const char *dst_tela = "ERROR-dst_tela"; 65 66#define SRC (aliasing == 0 ? mp->src_telno : src_tela) 67#define DST (aliasing == 0 ? mp->dst_telno : dst_tela) 68 69 if (aliasing) 70 { 71 src_tela = get_alias(mp->src_telno); 72 dst_tela = get_alias(mp->dst_telno); 73 } 74 75 if ((cep = find_matching_entry_incoming(mp, len)) == NULL) 76 { 77 /* log message generated in find_matching_entry_incoming() */ 78 sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0); 79 handle_scrprs(mp->header.cdid, mp->scr_ind, mp->prs_ind, SRC); 80 return; 81 } 82 83 if (cep->cdid != CDID_UNUSED && cep->cdid != CDID_RESERVED) 84 { 85 /* 86 * This is an incoming call on a number we just dialed out. 87 * Stop our dial-out and accept the incoming call. 88 */ 89 if (cep->saved_call.cdid != CDID_UNUSED && 90 cep->saved_call.cdid != CDID_RESERVED) 91 { 92 int cdid; 93 94 /* disconnect old, not new */ 95 96 cdid = cep->cdid; 97 cep->cdid = cep->saved_call.cdid; 98 sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); 99 cep->cdid = cdid; 100 101 /* 102 * Shortcut the state machine and mark this 103 * entry as free 104 */ 105/* XXX */ cep->state = ST_IDLE; /* this is an invalid */ 106 /* transition, */ 107 /* so no next_state() */ 108 /* we have to wait here for an incoming */ 109 /* disconnect message !!! (-hm) */ 110 } 111 } 112 113 if (cep->inout == DIR_OUTONLY) 114 { 115 logit(LL_CHD, "%05d %s incoming call from %s to %s not allowed by configuration!", 116 mp->header.cdid, cep->name, SRC, DST); 117 sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0); 118 handle_scrprs(mp->header.cdid, mp->scr_ind, mp->prs_ind, SRC); 119 return; 120 } 121 122 cep->charge = 0; 123 cep->last_charge = 0; 124 125 switch (cep->dialin_reaction) 126 { 127 case REACT_ACCEPT: 128 logit(LL_CHD, "%05d %s accepting: incoming call from %s to %s", 129 mp->header.cdid, cep->name, SRC, DST); 130 decr_free_channels(find_ctrl_state(mp->controller)); 131 next_state(cep, EV_MCI); 132 break; 133 134 case REACT_REJECT: 135 logit(LL_CHD, "%05d %s rejecting: incoming call from %s to %s", 136 mp->header.cdid, cep->name, SRC, DST); 137 sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT, 138 (CAUSET_I4B << 8) | CAUSE_I4B_REJECT); 139 cep->cdid = CDID_UNUSED; 140 break; 141 142 case REACT_IGNORE: 143 logit(LL_CHD, "%05d %s ignoring: incoming call from %s to %s", 144 mp->header.cdid, cep->name, SRC, DST); 145 sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0); 146 break; 147 148 case REACT_ANSWER: 149 decr_free_channels(find_ctrl_state(mp->controller)); 150 if (cep->alert) 151 { 152 if (mp->display) 153 { 154 logit(LL_CHD, "%05d %s alerting: incoming call from %s to %s (%s)", 155 mp->header.cdid, cep->name, SRC, DST, mp->display); 156 } 157 else 158 { 159 logit(LL_CHD, "%05d %s alerting: incoming call from %s to %s", 160 mp->header.cdid, cep->name, SRC, DST); 161 } 162 next_state(cep, EV_ALRT); 163 } 164 else 165 { 166 if (mp->display) 167 { 168 logit(LL_CHD, "%05d %s answering: incoming call from %s to %s (%s)", 169 mp->header.cdid, cep->name, SRC, DST, mp->display); 170 } 171 else 172 { 173 logit(LL_CHD, "%05d %s answering: incoming call from %s to %s", 174 mp->header.cdid, cep->name, SRC, DST); 175 } 176 next_state(cep, EV_MCI); 177 } 178 break; 179 180 case REACT_CALLBACK: 181 182#ifdef NOTDEF 183/*XXX reserve channel ??? */ decr_free_channels(mp->controller); 184#endif 185 if (cep->cdid == CDID_RESERVED) 186 { 187 logit(LL_CHD, "%05d %s reserved: incoming call from %s to %s", 188 mp->header.cdid, cep->name, SRC, DST); 189 sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT, 190#if 0 191 (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); 192#else 193 (CAUSET_I4B << 8) | CAUSE_I4B_REJECT); 194#endif 195 /* no state change */ 196 } 197 else 198 { 199 sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT, 200#if 0 201 (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); 202#else 203 (CAUSET_I4B << 8) | CAUSE_I4B_REJECT); 204#endif 205 if (cep->budget_callbackperiod && cep->budget_callbackncalls) 206 { 207 cep->budget_callback_req++; 208 cep->budget_calltype = 0; 209 if (cep->budget_callbackncalls_cnt == 0) 210 { 211 logit(LL_CHD, "%05d %s no budget: call from %s to %s", 212 mp->header.cdid, cep->name, SRC, DST); 213 cep->cdid = CDID_UNUSED; 214 cep->budget_callback_rej++; 215 break; 216 } 217 else 218 { 219 cep->budget_calltype = BUDGET_TYPE_CBACK; 220 } 221 } 222 223 logit(LL_CHD, "%05d %s callback: incoming call from %s to %s", 224 mp->header.cdid, cep->name, SRC, DST); 225 226 cep->last_release_time = time(NULL); 227 cep->cdid = CDID_RESERVED; 228 next_state(cep, EV_CBRQ); 229 } 230 break; 231 232 default: 233 logit(LL_WRN, "msg_connect_ind: unknown response type, tx SETUP_RESP_DNTCRE"); 234 sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0); 235 break; 236 } 237 handle_scrprs(mp->header.cdid, mp->scr_ind, mp->prs_ind, SRC); 238#undef SRC 239#undef DST 240} 241 242/*---------------------------------------------------------------------------* 243 * handle incoming CONNECT_ACTIVE_IND message 244 *---------------------------------------------------------------------------*/ 245void 246msg_connect_active_ind(msg_connect_active_ind_t *mp) 247{ 248 struct cfg_entry *cep; 249 250 if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL) 251 { 252 logit(LL_WRN, "msg_connect_active_ind: cdid not found!"); 253 return; 254 } 255 256 cep->isdncontrollerused = mp->controller; 257 cep->isdnchannelused = mp->channel; 258 259 cep->aoc_now = cep->connect_time = time(NULL); 260 cep->aoc_last = 0; 261 cep->aoc_diff = 0; 262 cep->aoc_valid = AOC_INVALID; 263 264 cep->local_disconnect = DISCON_REM; 265 266 cep->inbytes = INVALID; 267 cep->outbytes = INVALID; 268 cep->hangup = 0; 269 270 /* set the B-channel to active */ 271 272 if ((set_channel_busy(find_ctrl_state(cep->isdncontrollerused), cep->isdnchannelused)) == ERROR) 273 logit(LL_ERR, "msg_connect_active_ind: set_channel_busy failed!"); 274 275 if (cep->direction == DIR_OUT) 276 { 277 logit(LL_CHD, "%05d %s outgoing call active (ctl %d, ch %d, %s%d)", 278 cep->cdid, cep->name, 279 cep->isdncontrollerused, cep->isdnchannelused, 280 cep->usrdevicename, cep->usrdeviceunit); 281 282 if (cep->budget_calltype) 283 { 284 if (cep->budget_calltype == BUDGET_TYPE_CBACK) 285 { 286 cep->budget_callback_done++; 287 cep->budget_callbackncalls_cnt--; 288 DBGL(DL_BDGT, (logit(LL_DBG, "%s: new cback-budget = %d", 289 cep->name, cep->budget_callbackncalls_cnt))); 290 if (cep->budget_callbacks_file != NULL) 291 upd_callstat_file(cep->budget_callbacks_file, cep->budget_callbacksfile_rotate); 292 } 293 else if (cep->budget_calltype == BUDGET_TYPE_COUT) 294 { 295 cep->budget_callout_done++; 296 cep->budget_calloutncalls_cnt--; 297 DBGL(DL_BDGT, (logit(LL_DBG, "%s: new cout-budget = %d", 298 cep->name, cep->budget_calloutncalls_cnt))); 299 if (cep->budget_callouts_file != NULL) 300 upd_callstat_file(cep->budget_callouts_file, cep->budget_calloutsfile_rotate); 301 } 302 cep->budget_calltype = 0; 303 } 304 } 305 else 306 { 307 logit(LL_CHD, "%05d %s incoming call active (ctl %d, ch %d, %s%d)", 308 cep->cdid, cep->name, 309 cep->isdncontrollerused, cep->isdnchannelused, 310 cep->usrdevicename, cep->usrdeviceunit); 311 } 312 313#ifdef USE_CURSES 314 if (do_fullscreen) 315 display_connect(cep); 316#endif 317#ifdef I4B_EXTERNAL_MONITOR 318 if (do_monitor && accepted) 319 monitor_evnt_connect(cep); 320#endif 321 322 if (isdntime && (mp->datetime[0] != '\0')) 323 { 324 logit(LL_DMN, "date/time from exchange = %s", mp->datetime); 325 } 326 327 next_state(cep, EV_MCAI); 328} 329 330/*---------------------------------------------------------------------------* 331 * handle incoming PROCEEDING_IND message 332 *---------------------------------------------------------------------------*/ 333void 334msg_proceeding_ind(msg_proceeding_ind_t *mp) 335{ 336 struct cfg_entry *cep; 337 338 if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL) 339 { 340 logit(LL_WRN, "msg_proceeding_ind: cdid not found!"); 341 return; 342 } 343 344 cep->isdncontrollerused = mp->controller; 345 cep->isdnchannelused = mp->channel; 346 347 /* set the B-channels active */ 348 349 if ((set_channel_busy(find_ctrl_state(cep->isdncontrollerused), cep->isdnchannelused)) == ERROR) 350 logit(LL_ERR, "msg_proceeding_ind: set_channel_busy failed!"); 351 352 logit(LL_CHD, "%05d %s outgoing call proceeding (ctl %d, ch %d)", 353 cep->cdid, cep->name, 354 cep->isdncontrollerused, cep->isdnchannelused); 355} 356 357/*---------------------------------------------------------------------------* 358 * handle incoming ALERT_IND message 359 *---------------------------------------------------------------------------*/ 360void 361msg_alert_ind(msg_alert_ind_t *mp) 362{ 363 struct cfg_entry *cep; 364 365 if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL) 366 { 367 logit(LL_WRN, "msg_alert_ind: cdid not found!"); 368 return; 369 } 370#ifdef NOTDEF 371 logit(LL_CHD, "%05d %s incoming alert", cep->cdid, cep->name); 372#endif 373} 374 375/*---------------------------------------------------------------------------* 376 * handle incoming L12STAT_IND message 377 *---------------------------------------------------------------------------*/ 378void 379msg_l12stat_ind(msg_l12stat_ind_t *ml) 380{ 381 struct isdn_ctrl_state * ctrl = find_ctrl_state(ml->controller); 382 if (ctrl == NULL) { 383 logit(LL_ERR, "msg_l12stat_ind: invalid controller number: %d !", ml->controller); 384 return; 385 } 386 387#ifdef USE_CURSES 388 if (do_fullscreen) 389 display_l12stat(ml->controller, ml->layer, ml->state); 390#endif 391#ifdef I4B_EXTERNAL_MONITOR 392 if (do_monitor && accepted) 393 monitor_evnt_l12stat(ml->controller, ml->layer, ml->state); 394#endif 395 396 DBGL(DL_CNST, (logit(LL_DBG, "msg_l12stat_ind: unit %d, layer %d, state %d", 397 ml->controller, ml->layer, ml->state))); 398 399 if (ml->layer == LAYER_ONE) 400 { 401 if (ml->state == LAYER_IDLE) 402 ctrl->l2stat = ml->state; 403 ctrl->l1stat = ml->state; 404 } 405 else if (ml->layer == LAYER_TWO) 406 { 407 if (ml->state == LAYER_ACTIVE) 408 ctrl->l1stat = ml->state; 409 ctrl->l2stat = ml->state; 410 } 411 else 412 { 413 logit(LL_ERR, "msg_l12stat_ind: invalid layer number [%d]!", ml->layer); 414 } 415} 416 417/*---------------------------------------------------------------------------* 418 * handle incoming TEIASG_IND message 419 *---------------------------------------------------------------------------*/ 420void 421msg_teiasg_ind(msg_teiasg_ind_t *mt) 422{ 423 struct isdn_ctrl_state *ctrl = find_ctrl_state(mt->controller); 424 425 if (ctrl == NULL) { 426 logit(LL_ERR, "msg_teiasg_ind: invalid controller number [%d]!", mt->controller); 427 return; 428 } 429 430#ifdef USE_CURSES 431 if (do_fullscreen) 432 display_tei(mt->controller, mt->tei); 433#endif 434#ifdef I4B_EXTERNAL_MONITOR 435 if (do_monitor && accepted) 436 monitor_evnt_tei(mt->controller, mt->tei); 437#endif 438 439 DBGL(DL_CNST, (logit(LL_DBG, "msg_teiasg_ind: unit %d, tei = %d", 440 mt->controller, mt->tei))); 441 442 ctrl->tei = mt->tei; 443} 444 445/*---------------------------------------------------------------------------* 446 * handle incoming PDEACT_IND message 447 *---------------------------------------------------------------------------*/ 448void 449msg_pdeact_ind(msg_pdeact_ind_t *md) 450{ 451 int isdnif = md->controller; 452 struct cfg_entry *cep; 453 struct isdn_ctrl_state * ctrl = find_ctrl_state(isdnif); 454 455#ifdef USE_CURSES 456 if (do_fullscreen) 457 { 458 display_l12stat(isdnif, LAYER_ONE, LAYER_IDLE); 459 display_l12stat(isdnif, LAYER_TWO, LAYER_IDLE); 460 display_tei(isdnif, -1); 461 } 462#endif 463#ifdef I4B_EXTERNAL_MONITOR 464 if (do_monitor && accepted) 465 { 466 monitor_evnt_l12stat(isdnif, LAYER_ONE, LAYER_IDLE); 467 monitor_evnt_l12stat(isdnif, LAYER_TWO, LAYER_IDLE); 468 monitor_evnt_tei(isdnif, -1); 469 } 470#endif 471 472 DBGL(DL_CNST, (logit(LL_DBG, "msg_pdeact_ind: BRI %d, persistent deactivation", isdnif))); 473 474 ctrl->l1stat = LAYER_IDLE; 475 ctrl->l2stat = LAYER_IDLE; 476 ctrl->tei = -1; 477 478 for (cep = get_first_cfg_entry(); cep; cep = NEXT_CFE(cep)) { 479 if (cep->cdid != CDID_UNUSED && 480 cep->isdncontrollerused == isdnif) { 481 482 if (cep->cdid == CDID_RESERVED) 483 { 484 cep->state = ST_IDLE; 485 cep->cdid = CDID_UNUSED; 486 continue; 487 } 488 489 cep->cdid = CDID_UNUSED; 490 491 cep->last_release_time = time(NULL); 492 493 SET_CAUSE_TYPE(cep->disc_cause, CAUSET_I4B); 494 SET_CAUSE_VAL(cep->disc_cause, CAUSE_I4B_L1ERROR); 495 496 if (cep->direction == DIR_OUT) 497 { 498 logit(LL_CHD, "%05d %s outgoing call disconnected (local)", 499 cep->cdid, cep->name); 500 } 501 else 502 { 503 logit(LL_CHD, "%05d %s incoming call disconnected (local)", 504 cep->cdid, cep->name); 505 } 506 507 logit(LL_CHD, "%05d %s cause %s", 508 cep->cdid, cep->name, print_i4b_cause(cep->disc_cause)); 509 510#ifdef USE_CURSES 511 if (do_fullscreen && (cep->connect_time > 0)) 512 display_disconnect(cep); 513#endif 514#ifdef I4B_EXTERNAL_MONITOR 515 if (do_monitor && accepted) 516 monitor_evnt_disconnect(cep); 517#endif 518 519 if (cep->disconnectprog) 520 exec_connect_prog(cep, cep->disconnectprog, 1); 521 522 if (cep->connect_time > 0) 523 { 524 if (cep->direction == DIR_OUT) 525 { 526 logit(LL_CHD, "%05d %s charging: %d units, %d seconds", 527 cep->cdid, cep->name, cep->charge, 528 (int)difftime(time(NULL), cep->connect_time)); 529 } 530 else 531 { 532 logit(LL_CHD, "%05d %s connected %d seconds", 533 cep->cdid, cep->name, 534 (int)difftime(time(NULL), cep->connect_time)); 535 } 536 537 if ((cep->inbytes != INVALID) && (cep->outbytes != INVALID)) 538 { 539 if ((cep->ioutbytes != cep->outbytes) || 540 (cep->iinbytes != cep->inbytes)) 541 { 542 logit(LL_CHD, "%05d %s accounting: in %d, out %d (in %d, out %d)", 543 cep->cdid, cep->name, 544 cep->inbytes, cep->outbytes, 545 cep->iinbytes, cep->ioutbytes); 546 } 547 else 548 { 549 logit(LL_CHD, "%05d %s accounting: in %d, out %d", 550 cep->cdid, cep->name, 551 cep->inbytes, cep->outbytes); 552 } 553 } 554 } 555 556 if (useacctfile && (cep->connect_time > 0)) 557 { 558 int con_secs; 559 char logdatetime[41]; 560 struct tm *tp; 561 562 con_secs = difftime(time(NULL), cep->connect_time); 563 564 tp = localtime(&cep->connect_time); 565 566 strftime(logdatetime,40,I4B_TIME_FORMAT,tp); 567 568 if (cep->inbytes != INVALID && cep->outbytes != INVALID) 569 { 570 fprintf(acctfp, "%s - %s %s %d (%d) (%d/%d)\n", 571 logdatetime, getlogdatetime(), 572 cep->name, cep->charge, con_secs, 573 cep->inbytes, cep->outbytes); 574 } 575 else 576 { 577 fprintf(acctfp, "%s - %s %s %d (%d)\n", 578 logdatetime, getlogdatetime(), 579 cep->name, cep->charge, con_secs); 580 } 581 } 582 583 /* set the B-channel inactive */ 584 585 if ((set_channel_idle(ctrl, cep->isdnchannelused)) == ERROR) 586 logit(LL_ERR, "msg_pdeact_ind: set_channel_idle failed!"); 587 588 incr_free_channels(ctrl); 589 590 cep->connect_time = 0; 591 592 cep->state = ST_IDLE; 593 } 594 } 595} 596 597/*---------------------------------------------------------------------------* 598 * handle incoming NEGCOMP_IND message 599 *---------------------------------------------------------------------------*/ 600void 601msg_negcomplete_ind(msg_negcomplete_ind_t *mp) 602{ 603 struct cfg_entry *cep; 604 605 if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL) 606 { 607 logit(LL_WRN, "msg_negcomp_ind: cdid not found"); 608 return; 609 } 610 611 if (cep->connectprog) 612 exec_connect_prog(cep, cep->connectprog, 0); 613} 614 615/*---------------------------------------------------------------------------* 616 * handle incoming IFSTATE_CHANGED indication 617 *---------------------------------------------------------------------------*/ 618void 619msg_ifstatechg_ind(msg_ifstatechg_ind_t *mp) 620{ 621 struct cfg_entry *cep; 622 623 if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL) 624 { 625 logit(LL_WRN, "msg_negcomp_ind: cdid not found"); 626 return; 627 } 628 629 logit(LL_DBG, "%s%d: switched to state %d", cep->usrdevicename, cep->usrdeviceunit, mp->state); 630} 631 632/*---------------------------------------------------------------------------* 633 * handle incoming DISCONNECT_IND message 634 *---------------------------------------------------------------------------*/ 635void 636msg_disconnect_ind(msg_disconnect_ind_t *mp) 637{ 638 struct cfg_entry *cep; 639 struct isdn_ctrl_state *ctrl; 640 641 if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL) 642 { 643 logit(LL_WRN, "msg_disconnect_ind: cdid not found"); 644 return; 645 } 646 647 /* is this an aborted out-call prematurely called back? */ 648 if (cep->saved_call.cdid == mp->header.cdid) 649 { 650 DBGL(DL_CNST, (logit(LL_DBG, "aborted outcall %05d disconnected", 651 mp->header.cdid))); 652 cep->saved_call.cdid = CDID_UNUSED; 653 654 ctrl = find_ctrl_state(cep->saved_call.controller); 655 set_channel_idle(ctrl, cep->saved_call.channel); 656 657 incr_free_channels(ctrl); 658 return; 659 } 660 661 cep->last_release_time = time(NULL); 662 cep->disc_cause = mp->cause; 663 664 if (cep->direction == DIR_OUT) 665 { 666 logit(LL_CHD, "%05d %s outgoing call disconnected %s", 667 cep->cdid, cep->name, 668 cep->local_disconnect == DISCON_LOC ? 669 "(local)" : "(remote)"); 670 } 671 else 672 { 673 logit(LL_CHD, "%05d %s incoming call disconnected %s", 674 cep->cdid, cep->name, 675 cep->local_disconnect == DISCON_LOC ? 676 "(local)" : "(remote)"); 677 } 678 679 logit(LL_CHD, "%05d %s cause %s", 680 cep->cdid, cep->name, print_i4b_cause(mp->cause)); 681 682#ifdef USE_CURSES 683 if (do_fullscreen && (cep->connect_time > 0)) 684 display_disconnect(cep); 685#endif 686#ifdef I4B_EXTERNAL_MONITOR 687 if (do_monitor && accepted) 688 monitor_evnt_disconnect(cep); 689#endif 690 691 if (cep->disconnectprog) 692 exec_connect_prog(cep, cep->disconnectprog, 1); 693 694 if (cep->connect_time > 0) 695 { 696 if (cep->direction == DIR_OUT) 697 { 698 logit(LL_CHD, "%05d %s charging: %d units, %d seconds", 699 cep->cdid, cep->name, cep->charge, 700 (int)difftime(time(NULL), cep->connect_time)); 701 } 702 else 703 { 704 logit(LL_CHD, "%05d %s connected %d seconds", 705 cep->cdid, cep->name, 706 (int)difftime(time(NULL), cep->connect_time)); 707 } 708 709 if ((cep->inbytes != INVALID) && (cep->outbytes != INVALID)) 710 { 711 if ((cep->ioutbytes != cep->outbytes) || 712 (cep->iinbytes != cep->inbytes)) 713 { 714 logit(LL_CHD, "%05d %s accounting: in %d, out %d (in %d, out %d)", 715 cep->cdid, cep->name, 716 cep->inbytes, cep->outbytes, 717 cep->iinbytes, cep->ioutbytes); 718 } 719 else 720 { 721 logit(LL_CHD, "%05d %s accounting: in %d, out %d", 722 cep->cdid, cep->name, 723 cep->inbytes, cep->outbytes); 724 } 725 } 726 } 727 728 if (useacctfile && (cep->connect_time > 0)) 729 { 730 int con_secs; 731 char logdatetime[41]; 732 struct tm *tp; 733 734 con_secs = difftime(time(NULL), cep->connect_time); 735 736 tp = localtime(&cep->connect_time); 737 738 strftime(logdatetime,40,I4B_TIME_FORMAT,tp); 739 740 if (cep->inbytes != INVALID && cep->outbytes != INVALID) 741 { 742 fprintf(acctfp, "%s - %s %s %d (%d) (%d/%d)\n", 743 logdatetime, getlogdatetime(), 744 cep->name, cep->charge, con_secs, 745 cep->inbytes, cep->outbytes); 746 } 747 else 748 { 749 fprintf(acctfp, "%s - %s %s %d (%d)\n", 750 logdatetime, getlogdatetime(), 751 cep->name, cep->charge, con_secs); 752 } 753 } 754 755 /* set the B-channel inactive */ 756 757 ctrl = find_ctrl_state(cep->isdncontrollerused); 758 set_channel_idle(ctrl, cep->isdnchannelused); 759 760 incr_free_channels(ctrl); 761 762 cep->connect_time = 0; 763 764 next_state(cep, EV_MDI); 765} 766 767/*---------------------------------------------------------------------------* 768 * handle incoming DIALOUT message 769 *---------------------------------------------------------------------------*/ 770void 771msg_dialout(msg_dialout_ind_t *mp) 772{ 773 struct cfg_entry *cep; 774 775 if ((cep = find_by_device_for_dialout(mp->driver, mp->driver_unit)) == NULL) 776 { 777 DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialout: config entry reserved or no match"))); 778 return; 779 } 780 781 DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialout: dial req from %s%d", cep->usrdevicename, mp->driver_unit))); 782 783 if (cep->inout == DIR_INONLY) 784 { 785 dialresponse(cep, DSTAT_INONLY); 786 return; 787 } 788 789 if (cep->budget_calloutperiod && cep->budget_calloutncalls) 790 { 791 cep->budget_calltype = 0; 792 cep->budget_callout_req++; 793 794 if (cep->budget_calloutncalls_cnt == 0) 795 { 796 logit(LL_CHD, "%05d %s no budget for calling out", 0, cep->name); 797 cep->budget_callout_rej++; 798 dialresponse(cep, DSTAT_TFAIL); 799 return; 800 } 801 else 802 { 803 cep->budget_calltype = BUDGET_TYPE_COUT; 804 } 805 } 806 807 if ((cep->cdid = get_cdid()) == 0) 808 { 809 DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialout: get_cdid() returned 0!"))); 810 return; 811 } 812 813 cep->charge = 0; 814 cep->last_charge = 0; 815 816 next_state(cep, EV_MDO); 817} 818 819/*---------------------------------------------------------------------------* 820 * handle incoming DIALOUTNUMBER message 821 *---------------------------------------------------------------------------*/ 822void 823msg_dialoutnumber(msg_dialoutnumber_ind_t *mp) 824{ 825 struct cfg_entry *cep; 826 827 if ((cep = find_by_device_for_dialoutnumber(mp->driver, mp->driver_unit, mp->cmdlen, mp->cmd)) == NULL) 828 { 829 DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialoutnumber: config entry reserved or no match"))); 830 return; 831 } 832 833 DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialoutnumber: dial req from %s%d", cep->usrdevicename, mp->driver_unit))); 834 835 if (cep->inout == DIR_INONLY) 836 { 837 dialresponse(cep, DSTAT_INONLY); 838 return; 839 } 840 841 if (cep->budget_calloutperiod && cep->budget_calloutncalls) 842 { 843 cep->budget_calltype = 0; 844 cep->budget_callout_req++; 845 846 if (cep->budget_calloutncalls_cnt == 0) 847 { 848 logit(LL_CHD, "%05d %s no budget for calling out", 0, cep->name); 849 cep->budget_callout_rej++; 850 dialresponse(cep, DSTAT_TFAIL); 851 return; 852 } 853 else 854 { 855 cep->budget_calltype = BUDGET_TYPE_COUT; 856 } 857 } 858 859 if ((cep->cdid = get_cdid()) == 0) 860 { 861 DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialoutnumber: get_cdid() returned 0!"))); 862 return; 863 } 864 865 cep->charge = 0; 866 cep->last_charge = 0; 867 868 next_state(cep, EV_MDO); 869} 870 871/*---------------------------------------------------------------------------* 872 * handle incoming DRVRDISC_REQ message 873 *---------------------------------------------------------------------------*/ 874void 875msg_drvrdisc_req(msg_drvrdisc_req_t *mp) 876{ 877 struct cfg_entry *cep; 878 879 DBGL(DL_DRVR, (logit(LL_DBG, "msg_drvrdisc_req for call %d", mp->header.cdid))); 880 881 if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL) 882 { 883 DBGL(DL_DRVR, (logit(LL_DBG, "msg_drvrdisc_req: config entry not found"))); 884 return; 885 } 886 next_state(cep, EV_DRQ); 887} 888 889/*---------------------------------------------------------------------------* 890 * handle incoming ACCOUNTING message 891 *---------------------------------------------------------------------------*/ 892void 893msg_accounting(msg_accounting_ind_t *mp) 894{ 895 struct cfg_entry *cep; 896 897 if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL) 898 { 899 logit(LL_WRN, "msg_accounting: no config entry found!"); 900 return; 901 } 902 903 cep->inbytes = mp->inbytes; 904 cep->iinbytes = mp->iinbytes; 905 cep->outbytes = mp->outbytes; 906 cep->ioutbytes = mp->ioutbytes; 907 cep->inbps = mp->inbps; 908 cep->outbps = mp->outbps; 909 910 if (mp->accttype == ACCT_DURING) 911 { 912#ifdef USE_CURSES 913 if (do_fullscreen) 914 display_acct(cep); 915#endif 916#ifdef I4B_EXTERNAL_MONITOR 917 if (do_monitor && accepted) 918 monitor_evnt_acct(cep); 919#endif 920 } 921} 922 923/*---------------------------------------------------------------------------* 924 * handle incoming CHARGING message 925 *---------------------------------------------------------------------------*/ 926void 927msg_charging_ind(msg_charging_ind_t *mp) 928{ 929 static const char *cttab[] = { 930 "invalid", 931 "AOCD", 932 "AOCE", 933 "estimated" }; 934 935 struct cfg_entry *cep; 936 937 if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL) 938 { 939 logit(LL_WRN, "msg_charging_ind: cdid not found"); 940 return; 941 } 942 943 if (mp->units_type < CHARGE_INVALID || mp->units_type > CHARGE_CALC) 944 { 945 logit(LL_ERR, "msg_charging: units_type %d out of range!", mp->units_type); 946 error_exit(1, "msg_charging: units_type %d out of range!", mp->units_type); 947 } 948 949 DBGL(DL_DRVR, (logit(LL_DBG, "msg_charging: %d unit(s) (%s)", 950 mp->units, cttab[mp->units_type]))); 951 952 cep->charge = mp->units; 953 954 switch (mp->units_type) 955 { 956 case CHARGE_AOCD: 957 if ((cep->unitlengthsrc == ULSRC_DYN) && 958 (cep->charge != cep->last_charge)) 959 { 960 cep->last_charge = cep->charge; 961 handle_charge(cep); 962 } 963 break; 964 965 case CHARGE_CALC: 966#ifdef USE_CURSES 967 if (do_fullscreen) 968 display_ccharge(cep, mp->units); 969#endif 970#ifdef I4B_EXTERNAL_MONITOR 971 if (do_monitor && accepted) 972 monitor_evnt_charge(cep, mp->units, 1); 973#endif 974 break; 975 } 976} 977 978/*---------------------------------------------------------------------------* 979 * handle incoming IDLE_TIMEOUT_IND message 980 *---------------------------------------------------------------------------*/ 981void 982msg_idle_timeout_ind(msg_idle_timeout_ind_t *mp) 983{ 984 struct cfg_entry *cep; 985 986 if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL) 987 { 988 logit(LL_WRN, "msg_idle_timeout_ind: cdid not found!"); 989 return; 990 } 991 992 cep->local_disconnect = DISCON_LOC; 993 994 DBGL(DL_DRVR, (logit(LL_DBG, "msg_idle_timeout_ind: idletimeout, kernel sent disconnect!"))); 995 996 check_and_kill(cep); 997} 998 999/*---------------------------------------------------------------------------* 1000 * handle incoming MSG_PACKET_IND message 1001 *---------------------------------------------------------------------------*/ 1002static char * 1003strapp(char *buf, char *lim, const char *txt) 1004{ 1005 while (*txt && buf < lim - 1) 1006 *buf++ = *txt++; 1007 *buf = '\0'; 1008 return buf; 1009} 1010 1011/*---------------------------------------------------------------------------* 1012 * handle incoming MSG_PACKET_IND message 1013 *---------------------------------------------------------------------------*/ 1014static char * 1015ipapp(char *buf, char *lim, unsigned long a) 1016{ 1017 unsigned long ma = ntohl(a); 1018 ssize_t n; 1019 1020 n = snprintf(buf, lim - buf, "%lu.%lu.%lu.%lu", (ma>>24)&0xFF, 1021 (ma>>16)&0xFF, (ma>>8)&0xFF, (ma)&0xFF); 1022 if (n > 0) 1023 return buf + n; 1024 else 1025 return NULL; 1026} 1027 1028/*---------------------------------------------------------------------------* 1029 * handle incoming MSG_PACKET_IND message 1030 *---------------------------------------------------------------------------*/ 1031void 1032msg_packet_ind(msg_packet_ind_t *mp) 1033{ 1034 struct cfg_entry *cep; 1035 struct ip *ip; 1036 u_char *proto_hdr; 1037 char tmp[80]; 1038 char *cptr = tmp; 1039 const char *name = "???"; 1040 1041 for (cep = get_first_cfg_entry(); cep; cep = NEXT_CFE(cep)) { 1042 if (cep->usrdevice == mp->driver && 1043 cep->usrdeviceunit == mp->driver_unit) 1044 { 1045 name = cep->name; 1046 break; 1047 } 1048 } 1049 1050 ip = (struct ip*)mp->pktdata; 1051 proto_hdr = mp->pktdata + ((ip->ip_hl)<<2); 1052 1053 if (ip->ip_p == IPPROTO_TCP) 1054 { 1055 struct tcphdr* tcp = (struct tcphdr*)proto_hdr; 1056 1057 cptr = strapp(cptr, tmp + sizeof(tmp), "TCP "); 1058 cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_src.s_addr); 1059 cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp), 1060 ":%u -> ", ntohs(tcp->th_sport)); 1061 cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_dst.s_addr); 1062 cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp), 1063 ":%u", ntohs(tcp->th_dport)); 1064 1065 if (tcp->th_flags & TH_FIN) 1066 cptr = strapp(cptr, tmp + sizeof(tmp), " FIN"); 1067 if (tcp->th_flags & TH_SYN) 1068 cptr = strapp(cptr, tmp + sizeof(tmp), " SYN"); 1069 if (tcp->th_flags & TH_RST) 1070 cptr = strapp(cptr, tmp + sizeof(tmp), " RST"); 1071 if (tcp->th_flags & TH_PUSH) 1072 cptr = strapp(cptr, tmp + sizeof(tmp), " PUSH"); 1073 if (tcp->th_flags & TH_ACK) 1074 cptr = strapp(cptr, tmp + sizeof(tmp), " ACK"); 1075 if (tcp->th_flags & TH_URG) 1076 cptr = strapp(cptr, tmp + sizeof(tmp), " URG"); 1077 } 1078 else if (ip->ip_p == IPPROTO_UDP) 1079 { 1080 struct udphdr* udp = (struct udphdr*)proto_hdr; 1081 1082 cptr = strapp(cptr, tmp + sizeof(tmp), "UDP "); 1083 cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_src.s_addr); 1084 cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp), 1085 ":%u -> ", ntohs(udp->uh_sport)); 1086 cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_dst.s_addr); 1087 cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp), 1088 ":%u", ntohs(udp->uh_dport)); 1089 } 1090 else if (ip->ip_p == IPPROTO_ICMP) 1091 { 1092 struct icmp* icmp = (struct icmp*)proto_hdr; 1093 1094 cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp), 1095 "ICMP:%u.%u", icmp->icmp_type, icmp->icmp_code); 1096 cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_src.s_addr); 1097 cptr = strapp(cptr, tmp + sizeof(tmp), " -> "); 1098 cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_dst.s_addr); 1099 } 1100 else 1101 { 1102 cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp), 1103 "PROTO=%u ", ip->ip_p); 1104 cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_src.s_addr); 1105 cptr = strapp(cptr, tmp + sizeof(tmp), " -> "); 1106 cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_dst.s_addr); 1107 } 1108 1109 logit(LL_PKT, "%s %s %u %s", name, mp->direction ? "send" : "recv", 1110 ntohs(ip->ip_len), tmp); 1111} 1112 1113/* 1114 * A new controller arrived or is gone away 1115 */ 1116void 1117msg_ctrl_ev_ind(msg_ctrl_ev_ind_t *mp) 1118{ 1119 logit(LL_DMN, "controller %d %s", mp->controller, mp->event?"attached":"detached"); 1120 if (mp->event) { 1121 /* new, add to controller list */ 1122 init_new_controller(mp->controller); 1123 init_single_controller_protocol(find_ctrl_state(mp->controller)); 1124 } else { 1125 /* controller gone, remove */ 1126 remove_ctrl_state(mp->controller); 1127 } 1128} 1129 1130/*---------------------------------------------------------------------------* 1131 * get a cdid from kernel 1132 *---------------------------------------------------------------------------*/ 1133int 1134get_cdid(void) 1135{ 1136 msg_cdid_req_t mcr; 1137 1138 mcr.cdid = 0; 1139 1140 if ((ioctl(isdnfd, I4B_CDID_REQ, &mcr)) < 0) 1141 { 1142 logit(LL_ERR, "get_cdid: ioctl I4B_CDID_REQ failed: %s", strerror(errno)); 1143 error_exit(1, "get_cdid: ioctl I4B_CDID_REQ failed: %s", strerror(errno)); 1144 } 1145 1146 return(mcr.cdid); 1147} 1148 1149/*---------------------------------------------------------------------------* 1150 * send message "connect request" to kernel 1151 *---------------------------------------------------------------------------*/ 1152int 1153sendm_connect_req(struct cfg_entry *cep) 1154{ 1155 msg_connect_req_t mcr; 1156 int ret; 1157 1158 cep->local_disconnect = DISCON_REM; 1159 1160 cep->unitlength = get_current_rate(cep, 1); 1161 1162 mcr.cdid = cep->cdid; 1163 1164 mcr.controller = cep->isdncontrollerused; 1165 mcr.channel = cep->isdnchannelused; 1166 mcr.txdelay = cep->isdntxdelout; 1167 1168 mcr.bprot = cep->b1protocol; 1169 1170 mcr.driver = cep->usrdevice; 1171 mcr.driver_unit = cep->usrdeviceunit; 1172 1173 /* setup the shorthold data */ 1174 mcr.shorthold_data.shorthold_algorithm = cep->shorthold_algorithm; 1175 mcr.shorthold_data.unitlen_time = cep->unitlength; 1176 mcr.shorthold_data.idle_time = cep->idle_time_out; 1177 mcr.shorthold_data.earlyhup_time = cep->earlyhangup; 1178 1179 if (cep->unitlengthsrc == ULSRC_DYN) 1180 mcr.unitlen_method = ULEN_METHOD_DYNAMIC; 1181 else 1182 mcr.unitlen_method = ULEN_METHOD_STATIC; 1183 1184 strlcpy(mcr.dst_telno, cep->remote_phone_dialout, 1185 sizeof(mcr.dst_telno)); 1186 strlcpy(mcr.src_telno, cep->local_phone_dialout, sizeof(mcr.src_telno)); 1187 1188 cep->last_dial_time = time(NULL); 1189 cep->direction = DIR_OUT; 1190 1191 DBGL(DL_CNST, (logit(LL_DBG, "sendm_connect_req: ctrl = %d, chan = %d", cep->isdncontrollerused, cep->isdnchannelused))); 1192 1193 if ((ret = ioctl(isdnfd, I4B_CONNECT_REQ, &mcr)) < 0) 1194 { 1195 logit(LL_ERR, "sendm_connect_req: ioctl I4B_CONNECT_REQ failed: %s", strerror(errno)); 1196 error_exit(1, "sendm_connect_req: ioctl I4B_CONNECT_REQ failed: %s", strerror(errno)); 1197 } 1198 1199 decr_free_channels(find_ctrl_state(cep->isdncontrollerused)); 1200 1201 logit(LL_CHD, "%05d %s dialing out from %s to %s", 1202 cep->cdid, 1203 cep->name, 1204 aliasing ? get_alias(cep->local_phone_dialout) : cep->local_phone_dialout, 1205 aliasing ? get_alias(cep->remote_phone_dialout) : cep->remote_phone_dialout); 1206 1207 return(ret); 1208} 1209 1210/*---------------------------------------------------------------------------* 1211 * send message "connect response" to kernel 1212 *---------------------------------------------------------------------------*/ 1213int 1214sendm_connect_resp(struct cfg_entry *cep, int cdid, int response, cause_t cause) 1215{ 1216 msg_connect_resp_t mcr; 1217 int ret; 1218 1219 mcr.cdid = cdid; 1220 1221 mcr.response = response; 1222 1223 if (response == SETUP_RESP_REJECT) 1224 { 1225 mcr.cause = cause; 1226 DBGL(DL_DRVR, (logit(LL_DBG, "sendm_connect_resp: reject, cause=0x%x", cause))); 1227 } 1228 else if (response == SETUP_RESP_ACCEPT) 1229 { 1230 cep->direction = DIR_IN; 1231 1232 mcr.txdelay = cep->isdntxdelin; 1233 1234 mcr.bprot = cep->b1protocol; 1235 1236 mcr.driver = cep->usrdevice; 1237 mcr.driver_unit = cep->usrdeviceunit; 1238 1239 mcr.max_idle_time = cep->idle_time_in; 1240 1241 DBGL(DL_DRVR, (logit(LL_DBG, "sendm_connect_resp: accept"))); 1242 } 1243 1244 if ((ret = ioctl(isdnfd, I4B_CONNECT_RESP, &mcr)) < 0) 1245 { 1246 logit(LL_ERR, "sendm_connect_resp: ioctl I4B_CONNECT_RESP failed: %s", strerror(errno)); 1247 error_exit(1, "sendm_connect_resp: ioctl I4B_CONNECT_RESP failed: %s", strerror(errno)); 1248 } 1249 return(ret); 1250} 1251 1252/*---------------------------------------------------------------------------* 1253 * send message "disconnect request" to kernel 1254 *---------------------------------------------------------------------------*/ 1255int 1256sendm_disconnect_req(struct cfg_entry *cep, cause_t cause) 1257{ 1258 msg_discon_req_t mcr; 1259 int ret = 0; 1260 1261 mcr.cdid = cep->cdid; 1262 1263 mcr.cause = cause; 1264 1265 cep->local_disconnect = DISCON_LOC; 1266 1267 if ((ret = ioctl(isdnfd, I4B_DISCONNECT_REQ, &mcr)) < 0) 1268 { 1269 logit(LL_ERR, "sendm_disconnect_req: ioctl I4B_DISCONNECT_REQ failed: %s", strerror(errno)); 1270 } 1271 else 1272 { 1273 DBGL(DL_DRVR, (logit(LL_DBG, "sendm_disconnect_req: sent DISCONNECT_REQ"))); 1274 } 1275 return(ret); 1276} 1277 1278/*---------------------------------------------------------------------------* 1279 * send message "alert request" to kernel 1280 *---------------------------------------------------------------------------*/ 1281int 1282sendm_alert_req(struct cfg_entry *cep) 1283{ 1284 msg_alert_req_t mar; 1285 int ret; 1286 1287 mar.cdid = cep->cdid; 1288 1289 if ((ret = ioctl(isdnfd, I4B_ALERT_REQ, &mar)) < 0) 1290 { 1291 logit(LL_ERR, "sendm_alert_req: ioctl I4B_ALERT_REQ failed: %s", strerror(errno)); 1292 error_exit(1, "sendm_alert_req: ioctl I4B_ALERT_REQ failed: %s", strerror(errno)); 1293 } 1294 else 1295 { 1296 DBGL(DL_DRVR, (logit(LL_DBG, "sendm_alert_req: sent ALERT_REQ"))); 1297 } 1298 return(ret); 1299} 1300 1301/* EOF */ 1302