2 * Copyright (c) 1997, 1999 Hellmuth Michaelis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 *---------------------------------------------------------------------------
27 * i4b daemon - misc support routines
28 * ----------------------------------
30 * $Id: support.c,v 1.63 1999/12/13 21:25:25 hm Exp $
34 * last edit-date: [Mon Dec 13 21:49:05 1999]
36 *---------------------------------------------------------------------------*/
40 /*---------------------------------------------------------------------------*
41 * find an active entry by driver type and driver unit
42 *---------------------------------------------------------------------------*/
44 find_active_entry_by_driver(int drivertype, int driverunit)
46 cfg_entry_t *cep = NULL;
49 for(i=0; i < nentries; i++)
51 cep = &cfg_entry_tab[i]; /* ptr to config entry */
53 if(!((cep->usrdevicename == drivertype) &&
54 (cep->usrdeviceunit == driverunit)))
61 if(cep->cdid == CDID_UNUSED)
63 DBGL(DL_MSG, (log(LL_DBG, "find_active_entry_by_driver: entry %d [%s%d], cdid=CDID_UNUSED !",
64 i, bdrivername(drivertype), driverunit)));
67 else if(cep->cdid == CDID_RESERVED)
69 DBGL(DL_MSG, (log(LL_DBG, "find_active_entry_by_driver: entry %d [%s%d], cdid=CDID_RESERVED!",
70 i, bdrivername(drivertype), driverunit)));
78 /*---------------------------------------------------------------------------*
79 * find entry by drivertype and driverunit and setup for dialing out
80 *---------------------------------------------------------------------------*/
82 find_by_device_for_dialout(int drivertype, int driverunit)
84 cfg_entry_t *cep = NULL;
87 for(i=0; i < nentries; i++)
89 cep = &cfg_entry_tab[i]; /* ptr to config entry */
91 /* compare driver type and unit */
93 if(!((cep->usrdevicename == drivertype) &&
94 (cep->usrdeviceunit == driverunit)))
99 /* found, check if already reserved */
101 if(cep->cdid == CDID_RESERVED)
103 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: entry %d, cdid reserved!", i)));
107 /* check if this entry is already in use ? */
109 if(cep->cdid != CDID_UNUSED)
111 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: entry %d, cdid in use", i)));
115 if((setup_dialout(cep)) == GOOD)
117 /* found an entry to be used for calling out */
119 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: found entry %d!", i)));
124 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: entry %d, setup_dialout() failed!", i)));
129 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: no entry found!")));
133 /*---------------------------------------------------------------------------*
134 * find entry by drivertype and driverunit and setup for dialing out
135 *---------------------------------------------------------------------------*/
137 find_by_device_for_dialoutnumber(int drivertype, int driverunit, int cmdlen, char *cmd)
139 cfg_entry_t *cep = NULL;
142 for(i=0; i < nentries; i++)
144 cep = &cfg_entry_tab[i]; /* ptr to config entry */
146 /* compare driver type and unit */
148 if(!((cep->usrdevicename == drivertype) &&
149 (cep->usrdeviceunit == driverunit)))
154 /* found, check if already reserved */
156 if(cep->cdid == CDID_RESERVED)
158 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, cdid reserved!", i)));
162 /* check if this entry is already in use ? */
164 if(cep->cdid != CDID_UNUSED)
166 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, cdid in use", i)));
170 /* check number and copy to cep->remote_numbers[] */
172 for(j = 0; j < cmdlen; j++)
174 if(!(isdigit(*(cmd+j))))
176 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, dial string contains non-digit at pos %d", i, j)));
179 /* fill in number to dial */
180 cep->remote_numbers[0].number[j] = *(cmd+j);
182 cep->remote_numbers[0].number[j] = '\0';
183 cep->remote_numbers_count = 1;
185 if((setup_dialout(cep)) == GOOD)
187 /* found an entry to be used for calling out */
189 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: found entry %d!", i)));
194 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, setup_dialout() failed!", i)));
199 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: no entry found!")));
203 /*---------------------------------------------------------------------------*
204 * find entry by drivertype and driverunit and setup for dialing out
205 *---------------------------------------------------------------------------*/
207 setup_dialout(cfg_entry_t *cep)
209 /* check controller operational */
211 if((get_controller_state(cep->isdncontroller)) != CTRL_UP)
213 DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, controller is down", cep->name)));
217 cep->isdncontrollerused = cep->isdncontroller;
219 /* check channel available */
221 switch(cep->isdnchannel)
225 if((ret_channel_state(cep->isdncontroller, cep->isdnchannel)) != CHAN_IDLE)
227 DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, channel not free", cep->name)));
230 cep->isdnchannelused = cep->isdnchannel;
234 if(((ret_channel_state(cep->isdncontroller, CHAN_B1)) != CHAN_IDLE) &&
235 ((ret_channel_state(cep->isdncontroller, CHAN_B2)) != CHAN_IDLE))
237 DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, no channel free", cep->name)));
240 cep->isdnchannelused = CHAN_ANY;
244 DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, channel undefined", cep->name)));
249 DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s ok!", cep->name)));
251 /* preset disconnect cause */
253 SET_CAUSE_TYPE(cep->disc_cause, CAUSET_I4B);
254 SET_CAUSE_VAL(cep->disc_cause, CAUSE_I4B_NORMAL);
259 /*---------------------------------------------------------------------------*
260 * find entry by drivertype and driverunit
261 *---------------------------------------------------------------------------*/
263 get_cep_by_driver(int drivertype, int driverunit)
265 cfg_entry_t *cep = NULL;
268 for(i=0; i < nentries; i++)
270 cep = &cfg_entry_tab[i]; /* ptr to config entry */
272 if(!((cep->usrdevicename == drivertype) &&
273 (cep->usrdeviceunit == driverunit)))
278 DBGL(DL_MSG, (log(LL_DBG, "get_cep_by_driver: found entry %d!", i)));
284 /*---------------------------------------------------------------------------*
285 * find a matching entry for an incoming call
287 * - not found/no match: log output with LL_CHD and return NULL
288 * - found/match: make entry in free cep, return address
289 *---------------------------------------------------------------------------*/
291 find_matching_entry_incoming(msg_connect_ind_t *mp)
293 cfg_entry_t *cep = NULL;
296 /* check for CW (call waiting) early */
298 if(mp->channel == CHAN_NO)
302 char *src_tela = "ERROR-src_tela";
303 char *dst_tela = "ERROR-dst_tela";
305 src_tela = get_alias(mp->src_telno);
306 dst_tela = get_alias(mp->dst_telno);
308 log(LL_CHD, "%05d <unknown> CW from %s to %s (no channel free)",
309 mp->header.cdid, src_tela, dst_tela);
313 log(LL_CHD, "%05d <unknown> call waiting from %s to %s (no channel free)",
314 mp->header.cdid, mp->src_telno, mp->dst_telno);
319 for(i=0; i < nentries; i++)
322 cep = &cfg_entry_tab[i]; /* ptr to config entry */
324 /* check my number */
326 if(strncmp(cep->local_phone_incoming, mp->dst_telno, strlen(cep->local_phone_incoming)))
328 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, myno %s != incomingno %s", i,
329 cep->local_phone_incoming, mp->dst_telno)));
333 /* check all allowed remote number's for this entry */
335 for (n = 0; n < cep->incoming_numbers_count; n++)
337 incoming_number_t *in = &cep->remote_phone_incoming[n];
338 if(in->number[0] == '*')
340 if(strncmp(in->number, mp->src_telno, strlen(in->number)))
342 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, remno %s != incomingfromno %s", i,
343 in->number, mp->src_telno)));
348 if (n >= cep->incoming_numbers_count)
351 /* screening indicator XXX */
356 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - no screening indicator", mp->src_telno)));
360 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening user provided, not screened", mp->src_telno)));
364 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening user provided, verified & passed", mp->src_telno)));
368 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening user provided, verified & failed", mp->src_telno)));
372 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening network provided", mp->src_telno)));
376 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: ERROR %s - invalid screening indicator!", mp->src_telno)));
380 /* check b protocol */
382 if(cep->b1protocol != mp->bprot)
384 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, bprot %d != incomingprot %d", i,
385 cep->b1protocol, mp->bprot)));
389 /* is this entry currently in use ? */
391 if(cep->cdid != CDID_UNUSED)
393 if(cep->cdid == CDID_RESERVED)
395 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, cdid is reserved", i)));
397 else if (cep->dialin_reaction == REACT_ACCEPT
398 && cep->dialouttype == DIALOUT_CALLEDBACK)
401 * We might consider doing this even if this is
402 * not a calledback config entry - BUT: there are
403 * severe race conditions and timinig problems
404 * ex. if both sides run I4B with no callback
405 * delay - both may shutdown the outgoing call
406 * and never be able to establish a connection.
407 * In the called-back case this should not happen.
409 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, incoming call for callback in progress (cdid %05d)", i, cep->cdid)));
411 /* save the current call state, we're going to overwrite it with the
412 * new incoming state below... */
413 cep->saved_call.cdid = cep->cdid;
414 cep->saved_call.controller = cep->isdncontrollerused;
415 cep->saved_call.channel = cep->isdnchannelused;
419 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, cdid in use", i)));
420 continue; /* yes, next */
424 /* check controller value ok */
426 if(mp->controller > ncontroller)
428 log(LL_CHD, "%05d %s incoming call with invalid controller %d",
429 mp->header.cdid, cep->name, mp->controller);
433 /* check controller marked up */
435 if((get_controller_state(mp->controller)) != CTRL_UP)
437 log(LL_CHD, "%05d %s incoming call, controller %d DOWN!",
438 mp->header.cdid, cep->name, mp->controller);
442 /* check channel he wants */
448 if((ret_channel_state(mp->controller, mp->channel)) != CHAN_IDLE)
450 log(LL_CHD, "%05d %s incoming call, channel %s not free!",
451 mp->header.cdid, cep->name, mp->channel == CHAN_B1 ? "B1" : "B2");
457 if(((ret_channel_state(mp->controller, CHAN_B1)) != CHAN_IDLE) &&
458 ((ret_channel_state(mp->controller, CHAN_B2)) != CHAN_IDLE))
460 log(LL_CHD, "%05d %s incoming call, no channel free!",
461 mp->header.cdid, cep->name);
467 log(LL_CHD, "%05d %s incoming call, call waiting (no channel available)!",
468 mp->header.cdid, cep->name);
473 log(LL_CHD, "%05d %s incoming call, ERROR, channel undefined!",
474 mp->header.cdid, cep->name);
479 /* found a matching entry */
481 cep->cdid = mp->header.cdid;
482 cep->isdncontrollerused = mp->controller;
483 cep->isdnchannelused = mp->channel;
484 /*XXX*/ cep->disc_cause = 0;
486 /* cp number to real one used */
488 strcpy(cep->real_phone_incoming, mp->src_telno);
490 /* copy display string */
492 strcpy(cep->display, mp->display);
494 /* entry currently down ? */
496 if(cep->state == ST_DOWN)
498 msg_updown_ind_t mui;
500 /* set interface up */
502 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, ", i)));
504 mui.driver = cep->usrdevicename;
505 mui.driver_unit = cep->usrdeviceunit;
506 mui.updown = SOFT_ENA;
508 if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
510 log(LL_ERR, "find_matching_entry_incoming: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
511 error_exit(1, "find_matching_entry_incoming: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
514 cep->down_retry_count = 0;
515 cep->state = ST_IDLE;
522 char *src_tela = "ERROR-src_tela";
523 char *dst_tela = "ERROR-dst_tela";
525 src_tela = get_alias(mp->src_telno);
526 dst_tela = get_alias(mp->dst_telno);
528 log(LL_CHD, "%05d Call from %s to %s",
529 mp->header.cdid, src_tela, dst_tela);
533 log(LL_CHD, "%05d <unknown> incoming call from %s to %s",
534 mp->header.cdid, mp->src_telno, mp->dst_telno);
539 /*---------------------------------------------------------------------------*
540 * return address of ACTIVE config entry by controller and channel
541 *---------------------------------------------------------------------------*/
543 get_cep_by_cc(int ctrlr, int chan)
547 if((chan != CHAN_B1) && (chan != CHAN_B2))
550 for(i=0; i < nentries; i++)
552 if((cfg_entry_tab[i].cdid != CDID_UNUSED) &&
553 (cfg_entry_tab[i].cdid != CDID_RESERVED) &&
554 (cfg_entry_tab[i].isdnchannelused == chan) &&
555 (cfg_entry_tab[i].isdncontrollerused == ctrlr) &&
556 ((ret_channel_state(ctrlr, chan)) == CHAN_RUN))
558 return(&cfg_entry_tab[i]);
564 /*---------------------------------------------------------------------------*
565 * return address of config entry identified by cdid
566 *---------------------------------------------------------------------------*/
568 get_cep_by_cdid(int cdid)
572 for(i=0; i < nentries; i++)
574 if(cfg_entry_tab[i].cdid == cdid
575 || cfg_entry_tab[i].saved_call.cdid == cdid)
576 return(&cfg_entry_tab[i]);
581 /*---------------------------------------------------------------------------*
582 * return b channel driver type name string
583 *---------------------------------------------------------------------------*/
585 bdrivername(int drivertype)
587 static char *bdtab[] = {
595 if(drivertype >= BDRV_RBCH && drivertype <= BDRV_IBC)
596 return(bdtab[drivertype]);
601 /*---------------------------------------------------------------------------*
602 * process AOCD charging messages
603 *---------------------------------------------------------------------------*/
605 handle_charge(cfg_entry_t *cep)
607 time_t now = time(NULL);
609 if(cep->aoc_last == 0) /* no last timestamp yet ? */
611 cep->aoc_last = now; /* add time stamp */
613 else if(cep->aoc_now == 0) /* no current timestamp yet ? */
615 cep->aoc_now = now; /* current timestamp */
619 cep->aoc_last = cep->aoc_now;
621 cep->aoc_diff = cep->aoc_now - cep->aoc_last;
622 cep->aoc_valid = AOC_VALID;
630 #ifdef I4B_EXTERNAL_MONITOR
631 if(do_monitor && accepted)
632 monitor_evnt_charge(cep, cep->charge, 0);
635 if(cep->aoc_valid == AOC_VALID)
637 if(cep->aoc_diff != cep->unitlength)
639 DBGL(DL_MSG, (log(LL_DBG, "handle_charge: AOCD unit length updated %d -> %d secs", cep->unitlength, cep->aoc_diff)));
641 cep->unitlength = cep->aoc_diff;
648 DBGL(DL_MSG, (log(LL_DBG, "handle_charge: AOCD unit length still %d secs", cep->unitlength)));
654 /*---------------------------------------------------------------------------*
655 * update kernel idle_time, earlyhup_time and unitlen_time
656 *---------------------------------------------------------------------------*/
658 unitlen_chkupd(cfg_entry_t *cep)
660 msg_timeout_upd_t tupd;
662 tupd.cdid = cep->cdid;
664 /* init the short hold data based on the shorthold algorithm type */
666 switch(cep->shorthold_algorithm)
669 tupd.shorthold_data.shorthold_algorithm = SHA_FIXU;
670 tupd.shorthold_data.unitlen_time = cep->unitlength;
671 tupd.shorthold_data.idle_time = cep->idle_time_out;
672 tupd.shorthold_data.earlyhup_time = cep->earlyhangup;
676 tupd.shorthold_data.shorthold_algorithm = SHA_VARU;
677 tupd.shorthold_data.unitlen_time = cep->unitlength;
678 tupd.shorthold_data.idle_time = cep->idle_time_out;
679 tupd.shorthold_data.earlyhup_time = 0;
682 log(LL_ERR, "unitlen_chkupd bad shorthold_algorithm %d", cep->shorthold_algorithm );
687 if((ioctl(isdnfd, I4B_TIMEOUT_UPD, &tupd)) < 0)
689 log(LL_ERR, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno));
690 error_exit(1, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno));
694 /*--------------------------------------------------------------------------*
695 * this is intended to be called by do_exit and closes down all
696 * active connections before the daemon exits or is reconfigured.
697 *--------------------------------------------------------------------------*/
699 close_allactive(void)
702 cfg_entry_t *cep = NULL;
706 for (i = 0; i < ncontroller; i++)
708 if((get_controller_state(i)) != CTRL_UP)
711 if((ret_channel_state(i, CHAN_B1)) == CHAN_RUN)
713 if((cep = get_cep_by_cc(i, CHAN_B1)) != NULL)
717 display_disconnect(cep);
719 #ifdef I4B_EXTERNAL_MONITOR
720 monitor_evnt_disconnect(cep);
722 next_state(cep, EV_DRQ);
727 if((ret_channel_state(i, CHAN_B2)) == CHAN_RUN)
729 if((cep = get_cep_by_cc(i, CHAN_B2)) != NULL)
733 display_disconnect(cep);
735 #ifdef I4B_EXTERNAL_MONITOR
736 monitor_evnt_disconnect(cep);
738 next_state(cep, EV_DRQ);
746 log(LL_DMN, "close_allactive: waiting for all connections terminated");
751 /*--------------------------------------------------------------------------*
752 * set an interface up
753 *--------------------------------------------------------------------------*/
755 if_up(cfg_entry_t *cep)
757 msg_updown_ind_t mui;
759 /* set interface up */
761 DBGL(DL_MSG, (log(LL_DBG, "if_up: taking %s%d up", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
763 mui.driver = cep->usrdevicename;
764 mui.driver_unit = cep->usrdeviceunit;
765 mui.updown = SOFT_ENA;
767 if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
769 log(LL_ERR, "if_up: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
770 error_exit(1, "if_up: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
772 cep->down_retry_count = 0;
776 display_updown(cep, 1);
778 #ifdef I4B_EXTERNAL_MONITOR
779 monitor_evnt_updown(cep, 1);
784 /*--------------------------------------------------------------------------*
785 * set an interface down
786 *--------------------------------------------------------------------------*/
788 if_down(cfg_entry_t *cep)
790 msg_updown_ind_t mui;
792 /* set interface up */
794 DBGL(DL_MSG, (log(LL_DBG, "if_down: taking %s%d down", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
796 mui.driver = cep->usrdevicename;
797 mui.driver_unit = cep->usrdeviceunit;
798 mui.updown = SOFT_DIS;
800 if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
802 log(LL_ERR, "if_down: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
803 error_exit(1, "if_down: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
805 cep->went_down_time = time(NULL);
806 cep->down_retry_count = 0;
810 display_updown(cep, 0);
812 #ifdef I4B_EXTERNAL_MONITOR
813 monitor_evnt_updown(cep, 0);
818 /*--------------------------------------------------------------------------*
819 * send a dial response to (an interface in) the kernel
820 *--------------------------------------------------------------------------*/
822 dialresponse(cfg_entry_t *cep, int dstat)
824 msg_dialout_resp_t mdr;
826 static char *stattab[] = {
830 "dialout not allowed"
833 if(dstat < DSTAT_NONE || dstat > DSTAT_INONLY)
835 log(LL_ERR, "dialresponse: dstat out of range %d!", dstat);
839 mdr.driver = cep->usrdevicename;
840 mdr.driver_unit = cep->usrdeviceunit;
842 mdr.cause = cep->disc_cause;
844 if((ioctl(isdnfd, I4B_DIALOUT_RESP, &mdr)) < 0)
846 log(LL_ERR, "dialresponse: ioctl I4B_DIALOUT_RESP failed: %s", strerror(errno));
847 error_exit(1, "dialresponse: ioctl I4B_DIALOUT_RESP failed: %s", strerror(errno));
850 DBGL(DL_DRVR, (log(LL_DBG, "dialresponse: sent [%s]", stattab[dstat])));