2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.15 2009/04/16 05:56:32 lukem Exp $
34 * last edit-date: [Wed Oct 4 18:24:27 2000]
36 *---------------------------------------------------------------------------*/
40 static int isvalidtime(struct cfg_entry
*cep
);
42 static SLIST_HEAD(, isdn_ctrl_state
) isdn_ctrl_list
=
43 SLIST_HEAD_INITIALIZER(isdn_ctrl_list
);
45 static SIMPLEQ_HEAD(, cfg_entry
) cfg_entry_list
=
46 SIMPLEQ_HEAD_INITIALIZER(cfg_entry_list
);
48 /*---------------------------------------------------------------------------*
49 * find an active entry by driver type and driver unit
50 *---------------------------------------------------------------------------*/
52 find_active_entry_by_driver(int drivertype
, int driverunit
)
54 struct cfg_entry
*cep
= NULL
;
56 SIMPLEQ_FOREACH(cep
, &cfg_entry_list
, cfgq
) {
58 if (!((cep
->usrdevice
== drivertype
) &&
59 (cep
->usrdeviceunit
== driverunit
)))
64 /* check time interval */
66 if (isvalidtime(cep
) == 0)
68 DBGL(DL_MSG
, (logit(LL_DBG
, "find_active_entry_by_driver: entry %d, time not valid!", cep
->index
)));
74 if (cep
->cdid
== CDID_UNUSED
)
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
)));
80 else if (cep
->cdid
== CDID_RESERVED
)
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
)));
91 /*---------------------------------------------------------------------------*
92 * find entry by drivertype and driverunit and setup for dialing out
93 *---------------------------------------------------------------------------*/
95 find_by_device_for_dialout(int drivertype
, int driverunit
)
97 struct cfg_entry
*cep
;
99 SIMPLEQ_FOREACH(cep
, &cfg_entry_list
, cfgq
) {
101 /* compare driver type and unit */
103 if (!((cep
->usrdevice
== drivertype
) &&
104 (cep
->usrdeviceunit
== driverunit
)))
109 /* check time interval */
111 if (isvalidtime(cep
) == 0)
113 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialout: entry %d, time not valid!", cep
->index
)));
117 /* found, check if already reserved */
119 if (cep
->cdid
== CDID_RESERVED
)
121 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialout: entry %d, cdid reserved!", cep
->index
)));
125 /* check if this entry is already in use ? */
127 if (cep
->cdid
!= CDID_UNUSED
)
129 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialout: entry %d, cdid in use", cep
->index
)));
133 if ((setup_dialout(cep
)) == GOOD
)
135 /* found an entry to be used for calling out */
137 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialout: found entry %d!", cep
->index
)));
142 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialout: entry %d, setup_dialout() failed!", cep
->index
)));
147 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialout: no entry found!")));
151 /*---------------------------------------------------------------------------*
152 * find entry by drivertype and driverunit and setup for dialing out
153 *---------------------------------------------------------------------------*/
155 find_by_device_for_dialoutnumber(int drivertype
, int driverunit
, int cmdlen
, char *cmd
)
157 struct cfg_entry
*cep
;
160 SIMPLEQ_FOREACH(cep
, &cfg_entry_list
, cfgq
) {
162 /* compare driver type and unit */
164 if (!((cep
->usrdevice
== drivertype
) &&
165 (cep
->usrdeviceunit
== driverunit
)))
170 /* check time interval */
172 if (isvalidtime(cep
) == 0)
174 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialoutnumber: entry %d, time not valid!", cep
->index
)));
178 /* found, check if already reserved */
180 if (cep
->cdid
== CDID_RESERVED
)
182 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialoutnumber: entry %d, cdid reserved!", cep
->index
)));
186 /* check if this entry is already in use ? */
188 if (cep
->cdid
!= CDID_UNUSED
)
190 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialoutnumber: entry %d, cdid in use", cep
->index
)));
194 /* check number and copy to cep->remote_numbers[] */
196 for (j
= 0; j
< cmdlen
; j
++)
198 if (!(isdigit((unsigned char)*(cmd
+j
))))
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
)));
203 /* fill in number to dial */
204 cep
->remote_numbers
[0].number
[j
] = *(cmd
+j
);
206 cep
->remote_numbers
[0].number
[j
] = '\0';
207 cep
->remote_numbers_count
= 1;
209 if ((setup_dialout(cep
)) == GOOD
)
211 /* found an entry to be used for calling out */
213 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialoutnumber: found entry %d!", cep
->index
)));
218 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialoutnumber: entry %d, setup_dialout() failed!", cep
->index
)));
223 DBGL(DL_MSG
, (logit(LL_DBG
, "find_by_device_for_dialoutnumber: no entry found!")));
227 /*---------------------------------------------------------------------------*
228 * find entry by drivertype and driverunit and setup for dialing out
229 *---------------------------------------------------------------------------*/
231 setup_dialout(struct cfg_entry
*cep
)
233 struct isdn_ctrl_state
*ctrl
;
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
)
241 switch (cep
->isdnchannel
) {
243 for (i
= 0; i
< ctrl
->nbch
; i
++)
245 if (ret_channel_state(ctrl
, i
)
253 if (ret_channel_state(ctrl
, cep
->isdnchannel
)
258 /* this controller looks ok */
262 /* fixed controller in config, use that */
263 ctrl
= find_ctrl_state(cep
->isdncontroller
);
269 /* check controller operational */
271 if (get_controller_state(ctrl
) != CTRL_UP
)
273 DBGL(DL_MSG
, (logit(LL_DBG
, "setup_dialout: entry %s, controller is down", cep
->name
)));
277 cep
->isdncontrollerused
= ctrl
->isdnif
;
279 /* check channel available */
281 switch (cep
->isdnchannel
)
284 for (i
= 0; i
< ctrl
->nbch
; i
++)
286 if (ret_channel_state(ctrl
, i
) == CHAN_IDLE
)
291 DBGL(DL_MSG
, (logit(LL_DBG
, "setup_dialout: entry %s, no channel free", cep
->name
)));
294 cep
->isdnchannelused
= CHAN_ANY
;
298 if (ret_channel_state(ctrl
, cep
->isdnchannel
) != CHAN_IDLE
)
300 DBGL(DL_MSG
, (logit(LL_DBG
, "setup_dialout: entry %s, channel not free", cep
->name
)));
303 cep
->isdnchannelused
= cep
->isdnchannel
;
307 DBGL(DL_MSG
, (logit(LL_DBG
, "setup_dialout: entry %s ok!", cep
->name
)));
309 /* preset disconnect cause */
311 SET_CAUSE_TYPE(cep
->disc_cause
, CAUSET_I4B
);
312 SET_CAUSE_VAL(cep
->disc_cause
, CAUSE_I4B_NORMAL
);
317 /*---------------------------------------------------------------------------*
318 * find entry by drivertype and driverunit
319 *---------------------------------------------------------------------------*/
321 get_cep_by_driver(int drivertype
, int driverunit
)
323 struct cfg_entry
*cep
;
325 SIMPLEQ_FOREACH(cep
, &cfg_entry_list
, cfgq
) {
327 if (!((cep
->usrdevice
== drivertype
) &&
328 (cep
->usrdeviceunit
== driverunit
)))
333 /* check time interval */
335 if (isvalidtime(cep
) == 0)
337 DBGL(DL_MSG
, (logit(LL_DBG
, "get_cep_by_driver: entry %d, time not valid!", cep
->index
)));
341 DBGL(DL_MSG
, (logit(LL_DBG
, "get_cep_by_driver: found entry %d!", cep
->index
)));
347 /*---------------------------------------------------------------------------*
348 * find a matching entry for an incoming call
350 * - not found/no match: log output with LL_CHD and return NULL
351 * - found/match: make entry in free cep, return address
352 *---------------------------------------------------------------------------*/
354 find_matching_entry_incoming(msg_connect_ind_t
*mp
, int len
)
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
[] = {
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];
380 /* check for CW (call waiting) early */
382 if (mp
->channel
== CHAN_NO
)
386 const char *src_tela
= "ERROR-src_tela";
387 const char *dst_tela
= "ERROR-dst_tela";
389 src_tela
= get_alias(mp
->src_telno
);
390 dst_tela
= get_alias(mp
->dst_telno
);
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
);
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
);
403 SIMPLEQ_FOREACH(cep
, &cfg_entry_list
, cfgq
) {
406 struct isdn_ctrl_state
*ctrl
;
408 /* check my number */
410 if (strncmp(cep
->local_phone_incoming
, mp
->dst_telno
, strlen(cep
->local_phone_incoming
)))
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
)));
417 /* check all allowed remote number's for this entry */
419 for (n
= 0; n
< cep
->incoming_numbers_count
; n
++)
421 incoming_number_t
*in
= &cep
->remote_phone_incoming
[n
];
422 if (in
->number
[0] == '*')
424 if (strncmp(in
->number
, mp
->src_telno
, strlen(in
->number
)))
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
)));
432 if (n
>= cep
->incoming_numbers_count
)
435 /* check b protocol */
437 if (cep
->b1protocol
!= mp
->bprot
)
439 DBGL(DL_MSG
, (logit(LL_DBG
, "find_matching_entry_incoming: entry %d, bprot %d != incomingprot %d",
440 cep
->index
, cep
->b1protocol
, mp
->bprot
)));
444 /* is this entry currently in use ? */
446 if (cep
->cdid
!= CDID_UNUSED
)
448 if (cep
->cdid
== CDID_RESERVED
)
450 DBGL(DL_MSG
, (logit(LL_DBG
, "find_matching_entry_incoming: entry %d, cdid is reserved", cep
->index
)));
452 else if (cep
->dialin_reaction
== REACT_ACCEPT
453 && cep
->dialouttype
== DIALOUT_CALLEDBACK
)
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.
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
)));
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
;
474 DBGL(DL_MSG
, (logit(LL_DBG
, "find_matching_entry_incoming: entry %d, cdid in use", cep
->index
)));
475 continue; /* yes, next */
479 /* check controller value ok */
480 ctrl
= find_ctrl_state(mp
->controller
);
484 logit(LL_CHD
, "%05d %s incoming call with invalid controller %d",
485 mp
->header
.cdid
, cep
->name
, mp
->controller
);
489 /* check controller marked up */
491 if (get_controller_state(ctrl
) != CTRL_UP
)
493 logit(LL_CHD
, "%05d %s incoming call, controller %d DOWN!",
494 mp
->header
.cdid
, cep
->name
, mp
->controller
);
498 /* check channel he wants */
503 for (i
= 0; i
< ctrl
->nbch
; i
++)
504 if (ret_channel_state(ctrl
, i
) == CHAN_IDLE
)
508 logit(LL_CHD
, "%05d %s incoming call, no channel free!",
509 mp
->header
.cdid
, cep
->name
);
515 logit(LL_CHD
, "%05d %s incoming call, call waiting (no channel available)!",
516 mp
->header
.cdid
, cep
->name
);
521 if ((ret_channel_state(ctrl
, mp
->channel
)) != CHAN_IDLE
)
523 logit(LL_CHD
, "%05d %s incoming call, channel B%d not free!",
524 mp
->header
.cdid
, cep
->name
, mp
->channel
);
530 /* check time interval */
532 if (isvalidtime(cep
) == 0)
534 DBGL(DL_MSG
, (logit(LL_DBG
, "find_matching_entry_incoming: entry %d, time not valid!", cep
->index
)));
538 /* found a matching entry */
540 cep
->cdid
= mp
->header
.cdid
;
541 cep
->isdncontrollerused
= mp
->controller
;
542 cep
->isdnchannelused
= mp
->channel
;
543 /*XXX*/ cep
->disc_cause
= 0;
545 /* cp number to real one used */
547 strlcpy(cep
->real_phone_incoming
, mp
->src_telno
,
548 sizeof(cep
->real_phone_incoming
));
550 /* copy display string */
552 strlcpy(cep
->display
, mp
->display
, sizeof(cep
->display
));
554 /* entry currently down ? */
556 if (cep
->state
== ST_DOWN
)
558 msg_updown_ind_t mui
;
560 /* set interface up */
562 DBGL(DL_MSG
, (logit(LL_DBG
, "find_matching_entry_incoming: entry %d, ", cep
->index
)));
564 mui
.driver
= cep
->usrdevice
;
565 mui
.driver_unit
= cep
->usrdeviceunit
;
566 mui
.updown
= SOFT_ENA
;
568 if ((ioctl(isdnfd
, I4B_UPDOWN_IND
, &mui
)) < 0)
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
));
574 cep
->down_retry_count
= 0;
575 cep
->state
= ST_IDLE
;
582 const char *src_tela
= "ERROR-src_tela";
583 const char *dst_tela
= "ERROR-dst_tela";
585 src_tela
= get_alias(mp
->src_telno
);
586 dst_tela
= get_alias(mp
->dst_telno
);
588 logit(LL_CHD
, "%05d Call from %s (%s) to %s (%s)",
589 mp
->header
.cdid
, src_tela
, ntype
, dst_tela
, mp
->display
);
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
);
599 /*---------------------------------------------------------------------------*
600 * return address of ACTIVE config entry by controller and channel
601 *---------------------------------------------------------------------------*/
603 get_cep_by_cc(int ctrlr
, int chan
)
605 struct cfg_entry
*cep
;
606 struct isdn_ctrl_state
*cts
;
608 cts
= find_ctrl_state(ctrlr
);
612 if (chan
< 0 || chan
>= cts
->nbch
)
615 SIMPLEQ_FOREACH(cep
, &cfg_entry_list
, cfgq
) {
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
))
629 /*---------------------------------------------------------------------------*
630 * return address of config entry identified by cdid
631 *---------------------------------------------------------------------------*/
633 get_cep_by_cdid(int cdid
)
635 struct cfg_entry
*cep
;
637 SIMPLEQ_FOREACH(cep
, &cfg_entry_list
, cfgq
) {
638 if (cep
->cdid
== cdid
|| cep
->saved_call
.cdid
== cdid
)
644 /*---------------------------------------------------------------------------*
645 * process AOCD charging messages
646 *---------------------------------------------------------------------------*/
648 handle_charge(struct cfg_entry
*cep
)
650 time_t now
= time(NULL
);
652 if (cep
->aoc_last
== 0) /* no last timestamp yet ? */
654 cep
->aoc_last
= now
; /* add time stamp */
656 else if (cep
->aoc_now
== 0) /* no current timestamp yet ? */
658 cep
->aoc_now
= now
; /* current timestamp */
662 cep
->aoc_last
= cep
->aoc_now
;
664 cep
->aoc_diff
= cep
->aoc_now
- cep
->aoc_last
;
665 cep
->aoc_valid
= AOC_VALID
;
673 #ifdef I4B_EXTERNAL_MONITOR
674 if (do_monitor
&& accepted
)
675 monitor_evnt_charge(cep
, cep
->charge
, 0);
678 if (cep
->aoc_valid
== AOC_VALID
)
680 if (cep
->aoc_diff
!= cep
->unitlength
)
682 DBGL(DL_MSG
, (logit(LL_DBG
, "handle_charge: AOCD unit length updated %d -> %d secs", cep
->unitlength
, cep
->aoc_diff
)));
684 cep
->unitlength
= cep
->aoc_diff
;
691 DBGL(DL_MSG
, (logit(LL_DBG
, "handle_charge: AOCD unit length still %d secs", cep
->unitlength
)));
697 /*---------------------------------------------------------------------------*
698 * update kernel idle_time, earlyhup_time and unitlen_time
699 *---------------------------------------------------------------------------*/
701 unitlen_chkupd(struct cfg_entry
*cep
)
703 msg_timeout_upd_t tupd
;
705 tupd
.cdid
= cep
->cdid
;
707 /* init the short hold data based on the shorthold algorithm type */
709 switch (cep
->shorthold_algorithm
)
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
;
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;
725 logit(LL_ERR
, "unitlen_chkupd bad shorthold_algorithm %d", cep
->shorthold_algorithm
);
730 if ((ioctl(isdnfd
, I4B_TIMEOUT_UPD
, &tupd
)) < 0)
732 logit(LL_ERR
, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno
));
733 error_exit(1, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno
));
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 *--------------------------------------------------------------------------*/
742 close_allactive(void)
745 struct cfg_entry
*cep
= NULL
;
746 struct isdn_ctrl_state
*cst
;
750 SLIST_FOREACH(cst
, &isdn_ctrl_list
, ctrlq
) {
752 if ((get_controller_state(cst
)) != CTRL_UP
)
755 for (i
= 0; i
< cst
->nbch
; i
++)
757 if ((ret_channel_state(cst
, i
)) == CHAN_RUN
)
759 if ((cep
= get_cep_by_cc(cst
->isdnif
, i
))
764 display_disconnect(cep
);
766 #ifdef I4B_EXTERNAL_MONITOR
767 monitor_evnt_disconnect(cep
);
769 next_state(cep
, EV_DRQ
);
778 logit(LL_DMN
, "close_allactive: waiting for all connections terminated");
782 SIMPLEQ_FOREACH(cep
, &cfg_entry_list
, cfgq
) {
783 if (cep
->autoupdown
& AUTOUPDOWN_DONE
) {
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
);
792 ifr
.ifr_flags
&= ~IFF_UP
;
793 ioctl(s
, SIOCSIFFLAGS
, &ifr
);
796 cep
->autoupdown
&= ~AUTOUPDOWN_DONE
;
802 /*--------------------------------------------------------------------------*
803 * set an interface up
804 *--------------------------------------------------------------------------*/
806 if_up(struct cfg_entry
*cep
)
808 msg_updown_ind_t mui
;
810 /* set interface up */
812 DBGL(DL_MSG
, (logit(LL_DBG
, "if_up: taking %s%d up", cep
->usrdevicename
, cep
->usrdeviceunit
)));
814 mui
.driver
= cep
->usrdevice
;
815 mui
.driver_unit
= cep
->usrdeviceunit
;
816 mui
.updown
= SOFT_ENA
;
818 if ((ioctl(isdnfd
, I4B_UPDOWN_IND
, &mui
)) < 0)
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
));
823 cep
->down_retry_count
= 0;
827 display_updown(cep
, 1);
829 #ifdef I4B_EXTERNAL_MONITOR
830 monitor_evnt_updown(cep
, 1);
835 /*--------------------------------------------------------------------------*
836 * set an interface down
837 *--------------------------------------------------------------------------*/
839 if_down(struct cfg_entry
*cep
)
841 msg_updown_ind_t mui
;
843 /* set interface up */
845 DBGL(DL_MSG
, (logit(LL_DBG
, "if_down: taking %s%d down", cep
->usrdevicename
, cep
->usrdeviceunit
)));
847 mui
.driver
= cep
->usrdevice
;
848 mui
.driver_unit
= cep
->usrdeviceunit
;
849 mui
.updown
= SOFT_DIS
;
851 if ((ioctl(isdnfd
, I4B_UPDOWN_IND
, &mui
)) < 0)
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
));
856 cep
->went_down_time
= time(NULL
);
857 cep
->down_retry_count
= 0;
861 display_updown(cep
, 0);
863 #ifdef I4B_EXTERNAL_MONITOR
864 monitor_evnt_updown(cep
, 0);
869 /*--------------------------------------------------------------------------*
870 * send a dial response to (an interface in) the kernel
871 *--------------------------------------------------------------------------*/
873 dialresponse(struct cfg_entry
*cep
, int dstat
)
875 msg_dialout_resp_t mdr
;
877 static const char *stattab
[] = {
881 "dialout not allowed"
884 if (dstat
< DSTAT_NONE
|| dstat
> DSTAT_INONLY
)
886 logit(LL_ERR
, "dialresponse: dstat out of range %d!", dstat
);
890 mdr
.driver
= cep
->usrdevice
;
891 mdr
.driver_unit
= cep
->usrdeviceunit
;
893 mdr
.cause
= cep
->disc_cause
;
895 if ((ioctl(isdnfd
, I4B_DIALOUT_RESP
, &mdr
)) < 0)
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
));
901 DBGL(DL_DRVR
, (logit(LL_DBG
, "dialresponse: sent [%s]", stattab
[dstat
])));
904 /*--------------------------------------------------------------------------*
905 * screening/presentation indicator
906 *--------------------------------------------------------------------------*/
908 handle_scrprs(int cdid
, int scr
, int prs
, const char *caller
)
910 /* screening indicator */
912 if (scr
< SCR_NONE
|| scr
> SCR_NET
)
914 logit(LL_ERR
, "msg_connect_ind: invalid screening indicator value %d!", scr
);
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", };
927 logit(LL_CHD
, "%05d %s %s", cdid
, caller
, scrtab
[scr
]);
931 DBGL(DL_MSG
, (logit(LL_DBG
, "%s - %s", caller
, scrtab
[scr
])));
935 /* presentation indicator */
937 if (prs
< PRS_NONE
|| prs
> PRS_RESERVED
)
939 logit(LL_ERR
, "msg_connect_ind: invalid presentation indicator value %d!", prs
);
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" };
952 logit(LL_CHD
, "%05d %s %s", cdid
, caller
, prstab
[prs
]);
956 DBGL(DL_MSG
, (logit(LL_DBG
, "%s - %s", caller
, prstab
[prs
])));
961 /*--------------------------------------------------------------------------*
962 * check if the time is valid for an entry
963 *--------------------------------------------------------------------------*/
965 isvalidtime(struct cfg_entry
*cep
)
978 if (isholiday(tp
->tm_mday
, (tp
->tm_mon
)+1, (tp
->tm_year
)+1900))
980 DBGL(DL_MSG
, (logit(LL_DBG
, "isvalidtime: holiday %d.%d.%d", tp
->tm_mday
, (tp
->tm_mon
)+1, (tp
->tm_year
)+1900)));
985 if (cep
->day
& (1 << tp
->tm_wday
))
987 DBGL(DL_MSG
, (logit(LL_DBG
, "isvalidtime: day match")));
994 if (cep
->fromhr
==0 && cep
->frommin
==0 && cep
->tohr
==0 && cep
->tomin
==0)
996 DBGL(DL_MSG
, (logit(LL_DBG
, "isvalidtime: no time specified, match!")));
1000 if (cep
->tohr
< cep
->fromhr
)
1004 if ( (tp
->tm_hour
> cep
->fromhr
) ||
1005 (tp
->tm_hour
== cep
->fromhr
&& tp
->tm_min
> cep
->frommin
) )
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
)));
1017 if ( (tp
->tm_hour
< cep
->tohr
) ||
1018 (tp
->tm_hour
== cep
->tohr
&& tp
->tm_min
< cep
->tomin
) )
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
)));
1028 else if (cep
->fromhr
== cep
->tohr
)
1030 if (tp
->tm_min
>= cep
->frommin
&& tp
->tm_min
< cep
->tomin
)
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
)));
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
) )
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
)));
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
)));
1062 get_first_cfg_entry()
1064 return (SIMPLEQ_FIRST(&cfg_entry_list
));
1067 int count_cfg_entries()
1070 struct cfg_entry
*cfe
;
1073 SIMPLEQ_FOREACH(cfe
, &cfg_entry_list
, cfgq
)
1080 find_cfg_entry(int idx
)
1082 struct cfg_entry
*cep
;
1084 SIMPLEQ_FOREACH(cep
, &cfg_entry_list
, cfgq
)
1085 if (cep
->index
== idx
)
1091 add_cfg_entry(struct cfg_entry
*cfe
)
1093 struct cfg_entry
*cep
;
1096 SIMPLEQ_FOREACH(cep
, &cfg_entry_list
, cfgq
)
1097 if (cep
->index
> max
)
1101 SIMPLEQ_INSERT_TAIL(&cfg_entry_list
, cfe
, cfgq
);
1106 remove_all_cfg_entries()
1108 struct cfg_entry
*cep
;
1110 while (!SIMPLEQ_EMPTY(&cfg_entry_list
)) {
1111 cep
= SIMPLEQ_FIRST(&cfg_entry_list
);
1112 SIMPLEQ_REMOVE_HEAD(&cfg_entry_list
, cfgq
);
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
);
1127 struct isdn_ctrl_state
* get_first_ctrl_state()
1129 return SLIST_FIRST(&isdn_ctrl_list
);
1132 int count_ctrl_states()
1135 struct isdn_ctrl_state
*ctrl
;
1137 SLIST_FOREACH(ctrl
, &isdn_ctrl_list
, ctrlq
)
1143 void remove_all_ctrl_state()
1145 struct isdn_ctrl_state
*ctrl
;
1147 while (!SLIST_EMPTY(&isdn_ctrl_list
)) {
1148 ctrl
= SLIST_FIRST(&isdn_ctrl_list
);
1149 SLIST_REMOVE_HEAD(&isdn_ctrl_list
, ctrlq
);
1154 struct isdn_ctrl_state
*
1155 find_ctrl_state(int controller
)
1157 struct isdn_ctrl_state
*ctrl
;
1159 SLIST_FOREACH(ctrl
, &isdn_ctrl_list
, ctrlq
)
1160 if (ctrl
->isdnif
== controller
)
1166 add_ctrl_state(struct isdn_ctrl_state
*cstate
)
1168 SLIST_INSERT_HEAD(&isdn_ctrl_list
, cstate
, ctrlq
);
1173 remove_ctrl_state(int controller
)
1175 struct isdn_ctrl_state
*ctrl
= find_ctrl_state(controller
);
1176 struct cfg_entry
*cep
;
1182 if ((get_controller_state(ctrl
)) == CTRL_UP
) {
1184 for (i
= 0; i
< ctrl
->nbch
; i
++)
1186 if ((ret_channel_state(ctrl
, i
)) == CHAN_RUN
) {
1187 if ((cep
= get_cep_by_cc(controller
, i
))
1192 display_disconnect(cep
);
1194 #ifdef I4B_EXTERNAL_MONITOR
1195 monitor_evnt_disconnect(cep
);
1198 cep
->isdncontrollerused
= -1;
1199 cep
->isdnchannelused
= -1;
1200 cep
->state
= ST_IDLE
;
1206 SLIST_REMOVE(&isdn_ctrl_list
, ctrl
, isdn_ctrl_state
, ctrlq
);