Sync usage with man page.
[netbsd-mini2440.git] / usr.sbin / isdn / isdnd / support.c
blob05018cfe49a1881ce9b87d42b80bf824d9374634
1 /*
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
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.
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.
25 *---------------------------------------------------------------------------
27 * i4b daemon - misc support routines
28 * ----------------------------------
30 * $Id: support.c,v 1.15 2009/04/16 05:56:32 lukem Exp $
32 * $FreeBSD$
34 * last edit-date: [Wed Oct 4 18:24:27 2000]
36 *---------------------------------------------------------------------------*/
38 #include "isdnd.h"
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 *---------------------------------------------------------------------------*/
51 struct cfg_entry *
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)))
61 continue;
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)));
69 continue;
72 /* found */
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)));
78 return(NULL);
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)));
84 return(NULL);
86 return(cep);
88 return(NULL);
91 /*---------------------------------------------------------------------------*
92 * find entry by drivertype and driverunit and setup for dialing out
93 *---------------------------------------------------------------------------*/
94 struct cfg_entry *
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)))
106 continue;
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)));
114 continue;
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)));
122 return(NULL);
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)));
130 return(NULL);
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)));
138 return(cep);
140 else
142 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: entry %d, setup_dialout() failed!", cep->index)));
143 return(NULL);
147 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: no entry found!")));
148 return(NULL);
151 /*---------------------------------------------------------------------------*
152 * find entry by drivertype and driverunit and setup for dialing out
153 *---------------------------------------------------------------------------*/
154 struct cfg_entry *
155 find_by_device_for_dialoutnumber(int drivertype, int driverunit, int cmdlen, char *cmd)
157 struct cfg_entry *cep;
158 int j;
160 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) {
162 /* compare driver type and unit */
164 if (!((cep->usrdevice == drivertype) &&
165 (cep->usrdeviceunit == driverunit)))
167 continue;
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)));
175 continue;
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)));
183 return(NULL);
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)));
191 return(NULL);
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)));
201 return(NULL);
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)));
214 return(cep);
216 else
218 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, setup_dialout() failed!", cep->index)));
219 return(NULL);
223 DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: no entry found!")));
224 return(NULL);
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;
234 int i;
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++)
245 if (ret_channel_state(ctrl, i)
246 == CHAN_IDLE)
247 break;
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;
258 /* this controller looks ok */
259 break;
261 } else {
262 /* fixed controller in config, use that */
263 ctrl = find_ctrl_state(cep->isdncontroller);
266 if (ctrl == NULL)
267 return (ERROR);
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)));
274 return(ERROR);
277 cep->isdncontrollerused = ctrl->isdnif;
279 /* check channel available */
281 switch (cep->isdnchannel)
283 case CHAN_ANY:
284 for (i = 0; i < ctrl->nbch; i++)
286 if (ret_channel_state(ctrl, i) == CHAN_IDLE)
287 break;
289 if (i == ctrl->nbch)
291 DBGL(DL_MSG, (logit(LL_DBG, "setup_dialout: entry %s, no channel free", cep->name)));
292 return(ERROR);
294 cep->isdnchannelused = CHAN_ANY;
295 break;
297 default:
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)));
301 return(ERROR);
303 cep->isdnchannelused = cep->isdnchannel;
304 break;
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);
314 return(GOOD);
317 /*---------------------------------------------------------------------------*
318 * find entry by drivertype and driverunit
319 *---------------------------------------------------------------------------*/
320 struct cfg_entry *
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)))
330 continue;
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)));
338 continue;
341 DBGL(DL_MSG, (logit(LL_DBG, "get_cep_by_driver: found entry %d!", cep->index)));
342 return(cep);
344 return(NULL);
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 *---------------------------------------------------------------------------*/
353 struct cfg_entry *
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[] = {
360 "unknown",
361 "international",
362 "national",
363 "network specific",
364 "subscriber",
365 "abbreviated",
366 resvd_type,
367 resvd_type,
368 resvd_type
370 const char * ntype;
371 int i;
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;
380 /* check for CW (call waiting) early */
382 if (mp->channel == CHAN_NO)
384 if (aliasing)
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);
395 else
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);
400 return(NULL);
403 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) {
405 int n;
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)));
414 continue;
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] == '*')
423 break;
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)));
429 else
430 break;
432 if (n >= cep->incoming_numbers_count)
433 continue;
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)));
441 continue;
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;
472 else
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);
482 if (ctrl == NULL)
484 logit(LL_CHD, "%05d %s incoming call with invalid controller %d",
485 mp->header.cdid, cep->name, mp->controller);
486 return(NULL);
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);
495 return(NULL);
498 /* check channel he wants */
500 switch (mp->channel)
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)
508 logit(LL_CHD, "%05d %s incoming call, no channel free!",
509 mp->header.cdid, cep->name);
510 return(NULL);
512 break;
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;
520 default:
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);
525 return(NULL);
527 break;
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)));
535 continue;
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;
577 return(cep);
580 if (aliasing)
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);
591 else
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);
596 return(NULL);
599 /*---------------------------------------------------------------------------*
600 * return address of ACTIVE config entry by controller and channel
601 *---------------------------------------------------------------------------*/
602 struct cfg_entry *
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);
609 if (cts == NULL)
610 return(NULL);
612 if (chan < 0 || chan >= cts->nbch)
613 return(NULL);
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))
623 return (cep);
626 return(NULL);
629 /*---------------------------------------------------------------------------*
630 * return address of config entry identified by cdid
631 *---------------------------------------------------------------------------*/
632 struct cfg_entry *
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)
639 return(cep);
641 return(NULL);
644 /*---------------------------------------------------------------------------*
645 * process AOCD charging messages
646 *---------------------------------------------------------------------------*/
647 void
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 */
660 else
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;
668 #ifdef USE_CURSES
669 if (do_fullscreen)
670 display_charge(cep);
671 #endif
673 #ifdef I4B_EXTERNAL_MONITOR
674 if (do_monitor && accepted)
675 monitor_evnt_charge(cep, cep->charge, 0);
676 #endif
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;
686 unitlen_chkupd(cep);
688 else
690 #ifdef NOTDEF
691 DBGL(DL_MSG, (logit(LL_DBG, "handle_charge: AOCD unit length still %d secs", cep->unitlength)));
692 #endif
697 /*---------------------------------------------------------------------------*
698 * update kernel idle_time, earlyhup_time and unitlen_time
699 *---------------------------------------------------------------------------*/
700 void
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)
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;
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;
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 *--------------------------------------------------------------------------*/
741 void
742 close_allactive(void)
744 int i, j;
745 struct cfg_entry *cep = NULL;
746 struct isdn_ctrl_state *cst;
748 j = 0;
750 SLIST_FOREACH(cst, &isdn_ctrl_list, ctrlq) {
752 if ((get_controller_state(cst)) != CTRL_UP)
753 continue;
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))
760 != NULL)
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++;
776 if (j)
778 logit(LL_DMN, "close_allactive: waiting for all connections terminated");
779 sleep(5);
782 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) {
783 if (cep->autoupdown & AUTOUPDOWN_DONE) {
784 struct ifreq ifr;
785 int r, s;
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);
795 close(s);
796 cep->autoupdown &= ~AUTOUPDOWN_DONE;
802 /*--------------------------------------------------------------------------*
803 * set an interface up
804 *--------------------------------------------------------------------------*/
805 void
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;
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
835 /*--------------------------------------------------------------------------*
836 * set an interface down
837 *--------------------------------------------------------------------------*/
838 void
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;
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
869 /*--------------------------------------------------------------------------*
870 * send a dial response to (an interface in) the kernel
871 *--------------------------------------------------------------------------*/
872 void
873 dialresponse(struct cfg_entry *cep, int dstat)
875 msg_dialout_resp_t mdr;
877 static const char *stattab[] = {
878 "normal condition",
879 "temporary failure",
880 "permanent failure",
881 "dialout not allowed"
884 if (dstat < DSTAT_NONE || dstat > DSTAT_INONLY)
886 logit(LL_ERR, "dialresponse: dstat out of range %d!", dstat);
887 return;
890 mdr.driver = cep->usrdevice;
891 mdr.driver_unit = cep->usrdeviceunit;
892 mdr.stat = dstat;
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 *--------------------------------------------------------------------------*/
907 void
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);
916 else
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", };
925 if (extcallattr)
927 logit(LL_CHD, "%05d %s %s", cdid, caller, scrtab[scr]);
929 else
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);
941 else
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" };
950 if (extcallattr)
952 logit(LL_CHD, "%05d %s %s", cdid, caller, prstab[prs]);
954 else
956 DBGL(DL_MSG, (logit(LL_DBG, "%s - %s", caller, prstab[prs])));
961 /*--------------------------------------------------------------------------*
962 * check if the time is valid for an entry
963 *--------------------------------------------------------------------------*/
964 static int
965 isvalidtime(struct cfg_entry *cep)
967 time_t t;
968 struct tm *tp;
970 if (cep->day == 0)
971 return(1);
973 t = time(NULL);
974 tp = localtime(&t);
976 if (cep->day & HD)
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)));
981 goto dayok;
985 if (cep->day & (1 << tp->tm_wday))
987 DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: day match")));
988 goto dayok;
991 return(0);
993 dayok:
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!")));
997 return(1);
1000 if (cep->tohr < cep->fromhr)
1002 /* before 00:00 */
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)));
1012 return(1);
1015 /* after 00:00 */
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)));
1025 return(1);
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)));
1037 return(1);
1040 else
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)));
1050 return(1);
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)));
1058 return(0);
1061 struct cfg_entry *
1062 get_first_cfg_entry()
1064 return (SIMPLEQ_FIRST(&cfg_entry_list));
1067 int count_cfg_entries()
1069 int cnt;
1070 struct cfg_entry *cfe;
1072 cnt = 0;
1073 SIMPLEQ_FOREACH(cfe, &cfg_entry_list, cfgq)
1074 cnt++;
1076 return (cnt);
1079 struct cfg_entry *
1080 find_cfg_entry(int idx)
1082 struct cfg_entry *cep;
1084 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq)
1085 if (cep->index == idx)
1086 return cep;
1087 return NULL;
1091 add_cfg_entry(struct cfg_entry *cfe)
1093 struct cfg_entry *cep;
1094 int max = -1;
1096 SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq)
1097 if (cep->index > max)
1098 max = cep->index;
1100 cfe->index = max;
1101 SIMPLEQ_INSERT_TAIL(&cfg_entry_list, cfe, cfgq);
1102 return max;
1105 void
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);
1123 free(cep);
1127 struct isdn_ctrl_state * get_first_ctrl_state()
1129 return SLIST_FIRST(&isdn_ctrl_list);
1132 int count_ctrl_states()
1134 int cnt = 0;
1135 struct isdn_ctrl_state *ctrl;
1137 SLIST_FOREACH(ctrl, &isdn_ctrl_list, ctrlq)
1138 cnt++;
1140 return (cnt);
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);
1150 free(ctrl);
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)
1161 return ctrl;
1162 return NULL;
1166 add_ctrl_state(struct isdn_ctrl_state *cstate)
1168 SLIST_INSERT_HEAD(&isdn_ctrl_list, cstate, ctrlq);
1169 return 0;
1173 remove_ctrl_state(int controller)
1175 struct isdn_ctrl_state *ctrl = find_ctrl_state(controller);
1176 struct cfg_entry *cep;
1177 int i;
1179 if (ctrl == NULL)
1180 return 0;
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))
1188 != NULL)
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;
1206 SLIST_REMOVE(&isdn_ctrl_list, ctrl, isdn_ctrl_state, ctrlq);
1207 return 0;
1210 /* EOF */