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