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