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