]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/i4b/isdnd/support.c
This commit was generated by cvs2svn to compensate for changes in r53024,
[FreeBSD/FreeBSD.git] / usr.sbin / i4b / isdnd / support.c
1 /*
2  * Copyright (c) 1997, 1999 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$ 
31  *
32  *      last edit-date: [Mon Jul  5 15:29:22 1999]
33  *
34  *---------------------------------------------------------------------------*/
35
36 #include "isdnd.h"
37         
38 /*---------------------------------------------------------------------------*
39  *      find an active entry by driver type and driver unit
40  *---------------------------------------------------------------------------*/
41 cfg_entry_t *
42 find_active_entry_by_driver(int drivertype, int driverunit)
43 {
44         cfg_entry_t *cep = NULL;
45         int i;
46
47         for(i=0; i < nentries; i++)
48         {
49                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
50
51                 if(!((cep->usrdevicename == drivertype) &&
52                      (cep->usrdeviceunit == driverunit)))
53                 {
54                         continue;
55                 }
56
57                 /* found */
58                 
59                 if(cep->cdid == CDID_UNUSED)
60                 {
61                         DBGL(DL_MSG, (log(LL_DBG, "find_active_entry_by_driver: entry %d, cdid is CDID_UNUSED!", i)));
62                         return(NULL);
63                 }
64                 else if(cep->cdid == CDID_RESERVED)
65                 {
66                         DBGL(DL_MSG, (log(LL_DBG, "find_active_entry_by_driver: entry %d, cdid is CDID_RESERVED!", i)));
67                         return(NULL);
68                 }
69                 return(cep);
70         }
71         return(NULL);
72 }
73
74 /*---------------------------------------------------------------------------*
75  *      find entry by drivertype and driverunit and setup for dialing out
76  *---------------------------------------------------------------------------*/
77 cfg_entry_t *
78 find_by_device_for_dialout(int drivertype, int driverunit)
79 {
80         cfg_entry_t *cep = NULL;
81         int i;
82
83         for(i=0; i < nentries; i++)
84         {
85                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
86
87                 /* compare driver type and unit */
88
89                 if(!((cep->usrdevicename == drivertype) &&
90                      (cep->usrdeviceunit == driverunit)))
91                 {
92                         continue;
93                 }
94
95                 /* found, check if already reserved */
96                 
97                 if(cep->cdid == CDID_RESERVED)
98                 {
99                         DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: entry %d, cdid reserved!", i)));
100                         return(NULL);
101                 }
102
103                 /* check if this entry is already in use ? */
104                 
105                 if(cep->cdid != CDID_UNUSED)    
106                 {
107                         DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: entry %d, cdid in use", i)));
108                         return(NULL);
109                 }
110
111                 if((setup_dialout(cep)) == GOOD)
112                 {
113                         /* found an entry to be used for calling out */
114                 
115                         DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: found entry %d!", i)));
116                         return(cep);
117                 }
118                 else
119                 {
120                         DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: entry %d, setup_dialout() failed!", i)));
121                         return(NULL);
122                 }
123         }
124
125         DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: no entry found!")));
126         return(NULL);
127 }
128
129 /*---------------------------------------------------------------------------*
130  *      find entry by drivertype and driverunit and setup for dialing out
131  *---------------------------------------------------------------------------*/
132 cfg_entry_t *
133 find_by_device_for_dialoutnumber(int drivertype, int driverunit, int cmdlen, char *cmd)
134 {
135         cfg_entry_t *cep = NULL;
136         int i, j;
137
138         for(i=0; i < nentries; i++)
139         {
140                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
141
142                 /* compare driver type and unit */
143
144                 if(!((cep->usrdevicename == drivertype) &&
145                      (cep->usrdeviceunit == driverunit)))
146                 {
147                         continue;
148                 }
149
150                 /* found, check if already reserved */
151                 
152                 if(cep->cdid == CDID_RESERVED)
153                 {
154                         DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, cdid reserved!", i)));
155                         return(NULL);
156                 }
157
158                 /* check if this entry is already in use ? */
159                 
160                 if(cep->cdid != CDID_UNUSED)    
161                 {
162                         DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, cdid in use", i)));
163                         return(NULL);
164                 }
165
166                 /* check number and copy to cep->remote_numbers[] */
167                 
168                 for(j = 0; j < cmdlen; j++)
169                 {
170                         if(!(isdigit(*(cmd+j))))
171                         {
172                                 DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, dial string contains non-digit at pos %d", i, j)));
173                                 return(NULL);
174                         }
175                         /* fill in number to dial */
176                         cep->remote_numbers[0].number[j] = *(cmd+j);
177                 }                               
178                 cep->remote_numbers[0].number[j] = '\0';
179                 cep->remote_numbers_count = 1;
180
181                 if((setup_dialout(cep)) == GOOD)
182                 {
183                         /* found an entry to be used for calling out */
184                 
185                         DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: found entry %d!", i)));
186                         return(cep);
187                 }
188                 else
189                 {
190                         DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, setup_dialout() failed!", i)));
191                         return(NULL);
192                 }
193         }
194
195         DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialoutnumber: no entry found!")));
196         return(NULL);
197 }
198
199 /*---------------------------------------------------------------------------*
200  *      find entry by drivertype and driverunit and setup for dialing out
201  *---------------------------------------------------------------------------*/
202 int
203 setup_dialout(cfg_entry_t *cep)
204 {
205         /* check controller operational */
206
207         if((get_controller_state(cep->isdncontroller)) != CTRL_UP)
208         {
209                 DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, controller is down", cep->name)));
210                 return(ERROR);
211         }
212
213         cep->isdncontrollerused = cep->isdncontroller;
214
215         /* check channel available */
216
217         switch(cep->isdnchannel)
218         {
219                 case CHAN_B1:
220                 case CHAN_B2:
221                         if((ret_channel_state(cep->isdncontroller, cep->isdnchannel)) != CHAN_IDLE)
222                         {
223                                 DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, channel not free", cep->name)));
224                                 return(ERROR);
225                         }
226                         cep->isdnchannelused = cep->isdnchannel;
227                         break;
228
229                 case CHAN_ANY:
230                         if(((ret_channel_state(cep->isdncontroller, CHAN_B1)) != CHAN_IDLE) &&
231                            ((ret_channel_state(cep->isdncontroller, CHAN_B2)) != CHAN_IDLE))
232                         {
233                                 DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, no channel free", cep->name)));
234                                 return(ERROR);
235                         }
236                         cep->isdnchannelused = CHAN_ANY;
237                         break;
238
239                 default:
240                         DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, channel undefined", cep->name)));
241                         return(ERROR);
242                         break;
243         }
244
245         DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s ok!", cep->name)));
246
247         /* preset disconnect cause */
248         
249         SET_CAUSE_TYPE(cep->disc_cause, CAUSET_I4B);
250         SET_CAUSE_VAL(cep->disc_cause, CAUSE_I4B_NORMAL);
251         
252         return(GOOD);
253 }
254
255 /*---------------------------------------------------------------------------*
256  *      find entry by drivertype and driverunit
257  *---------------------------------------------------------------------------*/
258 cfg_entry_t *
259 get_cep_by_driver(int drivertype, int driverunit)
260 {
261         cfg_entry_t *cep = NULL;
262         int i;
263
264         for(i=0; i < nentries; i++)
265         {
266                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
267
268                 if(!((cep->usrdevicename == drivertype) &&
269                      (cep->usrdeviceunit == driverunit)))
270                 {
271                         continue;
272                 }
273
274                 DBGL(DL_MSG, (log(LL_DBG, "get_cep_by_driver: found entry %d!", i)));
275                 return(cep);
276         }
277         return(NULL);
278 }
279
280 /*---------------------------------------------------------------------------*
281  *      find a matching entry for an incoming call
282  *
283  *      - not found/no match: log output with LL_CHD and return NULL
284  *      - found/match: make entry in free cep, return address
285  *---------------------------------------------------------------------------*/
286 cfg_entry_t *
287 find_matching_entry_incoming(msg_connect_ind_t *mp)
288 {
289         cfg_entry_t *cep = NULL;
290         int i;
291
292         /* check for CW (call waiting) early */
293
294         if(mp->channel == CHAN_NO)
295         {
296                 if(aliasing)
297                 {
298                         char *src_tela = "ERROR-src_tela";
299                         char *dst_tela = "ERROR-dst_tela";
300         
301                         src_tela = get_alias(mp->src_telno);
302                         dst_tela = get_alias(mp->dst_telno);
303         
304                         log(LL_CHD, "%05d <unknown> CW from %s to %s (no channel free)",
305                                 mp->header.cdid, src_tela, dst_tela);
306                 }
307                 else
308                 {
309                         log(LL_CHD, "%05d <unknown> call waiting from %s to %s (no channel free)",
310                                 mp->header.cdid, mp->src_telno, mp->dst_telno);
311                 }
312                 return(NULL);
313         }
314         
315         for(i=0; i < nentries; i++)
316         {
317                 int n;
318                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
319
320                 /* check my number */
321
322                 if(strncmp(cep->local_phone_incoming, mp->dst_telno, strlen(cep->local_phone_incoming)))
323                 {
324                         DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, myno %s != incomingno %s", i,
325                                 cep->local_phone_incoming, mp->dst_telno)));
326                         continue;
327                 }
328
329                 /* check all allowed remote number's for this entry */
330
331                 for (n = 0; n < cep->incoming_numbers_count; n++)
332                 {
333                         incoming_number_t *in = &cep->remote_phone_incoming[n];
334                         if(in->number[0] == '*')
335                                 break;
336                         if(strncmp(in->number, mp->src_telno, strlen(in->number)))
337                         {
338                                 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, remno %s != incomingfromno %s", i,
339                                         in->number, mp->src_telno)));
340                         }
341                         else
342                                 break;
343                 }
344                 if (n >= cep->incoming_numbers_count)
345                         continue;
346
347                 /* screening indicator XXX */
348                 
349                 switch(mp->scr_ind)
350                 {
351                         case SCR_NONE:
352                                 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - no screening indicator", mp->src_telno)));
353                                 break;
354
355                         case SCR_USR_NOSC:
356                                 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening user provided, not screened", mp->src_telno)));
357                                 break;
358
359                         case SCR_USR_PASS:
360                                 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening user provided, verified & passed", mp->src_telno)));
361                                 break;
362
363                         case SCR_USR_FAIL:
364                                 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening user provided, verified & failed", mp->src_telno)));
365                                 break;
366
367                         case SCR_NET:
368                                 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening network provided", mp->src_telno)));
369                                 break;
370
371                         default:
372                                 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: ERROR %s - invalid screening indicator!", mp->src_telno)));
373                                 break;
374                 }
375                                 
376                 /* check b protocol */
377
378                 if(cep->b1protocol != mp->bprot)
379                 {
380                         DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, bprot %d != incomingprot %d", i,
381                                 cep->b1protocol, mp->bprot)));
382                         continue;
383                 }
384
385                 /* is this entry currently in use ? */
386
387                 if(cep->cdid != CDID_UNUSED)
388                 {
389                         if(cep->cdid == CDID_RESERVED)
390                         {
391                                 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, cdid is reserved", i)));
392                         }
393                         else if (cep->dialin_reaction == REACT_ACCEPT
394                                  && cep->dialouttype == DIALOUT_CALLEDBACK)
395                         {
396                                 /*
397                                  * We might consider doing this even if this is
398                                  * not a calledback config entry - BUT: there are
399                                  * severe race conditions and timinig problems
400                                  * ex. if both sides run I4B with no callback
401                                  * delay - both may shutdown the outgoing call
402                                  * and never be able to establish a connection.
403                                  * In the called-back case this should not happen.
404                                  */
405                                 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, incoming call for callback in progress (cdid %05d)", i, cep->cdid)));
406
407                                 /* save the current call state, we're going to overwrite it with the
408                                  * new incoming state below... */
409                                 cep->saved_call.cdid = cep->cdid;
410                                 cep->saved_call.controller = cep->isdncontrollerused;
411                                 cep->saved_call.channel = cep->isdnchannelused;
412                         }
413                         else
414                         {
415                                 DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, cdid in use", i)));
416                                 continue;       /* yes, next */
417                         }
418                 }
419
420                 /* check controller value ok */
421
422                 if(mp->controller > ncontroller)
423                 {
424                         log(LL_CHD, "%05d %s incoming call with invalid controller %d",
425                                 mp->header.cdid, cep->name, mp->controller);
426                         return(NULL);
427                 }
428
429                 /* check controller marked up */
430
431                 if((get_controller_state(mp->controller)) != CTRL_UP)
432                 {
433                         log(LL_CHD, "%05d %s incoming call, controller %d DOWN!",
434                                 mp->header.cdid, cep->name, mp->controller);
435                         return(NULL);
436                 }
437
438                 /* check channel he wants */
439
440                 switch(mp->channel)
441                 {
442                         case CHAN_B1:
443                         case CHAN_B2:
444                                 if((ret_channel_state(mp->controller, mp->channel)) != CHAN_IDLE)
445                                 {
446                                         log(LL_CHD, "%05d %s incoming call, channel %s not free!",
447                                                 mp->header.cdid, cep->name, mp->channel == CHAN_B1 ? "B1" : "B2");
448                                         return(NULL);
449                                 }
450                                 break;
451
452                         case CHAN_ANY:
453                                 if(((ret_channel_state(mp->controller, CHAN_B1)) != CHAN_IDLE) &&
454                                    ((ret_channel_state(mp->controller, CHAN_B2)) != CHAN_IDLE))
455                                 {
456                                         log(LL_CHD, "%05d %s incoming call, no channel free!",
457                                                 mp->header.cdid, cep->name);
458                                         return(NULL);
459                                 }
460                                 break;
461
462                         case CHAN_NO:
463                                 log(LL_CHD, "%05d %s incoming call, call waiting (no channel available)!",
464                                         mp->header.cdid, cep->name);
465                                 return(NULL);
466                                 break;
467
468                         default:
469                                 log(LL_CHD, "%05d %s incoming call, ERROR, channel undefined!",
470                                         mp->header.cdid, cep->name);
471                                 return(NULL);
472                                 break;
473                 }
474
475                 /* found a matching entry */
476
477                 cep->cdid = mp->header.cdid;
478                 cep->isdncontrollerused = mp->controller;
479                 cep->isdnchannelused = mp->channel;
480 /*XXX*/         cep->disc_cause = 0;
481
482                 /* cp number to real one used */
483                 
484                 strcpy(cep->real_phone_incoming, mp->src_telno);
485
486                 /* copy display string */
487                 
488                 strcpy(cep->display, mp->display);
489                 
490                 /* entry currently down ? */
491                 
492                 if(cep->state == ST_DOWN)
493                 {
494                         msg_updown_ind_t mui;
495                         
496                         /* set interface up */
497         
498                         DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, ", i)));
499         
500                         mui.driver = cep->usrdevicename;
501                         mui.driver_unit = cep->usrdeviceunit;
502                         mui.updown = SOFT_ENA;
503                         
504                         if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
505                         {
506                                 log(LL_ERR, "find_matching_entry_incoming: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
507                                 do_exit(1);
508                         }
509
510                         cep->down_retry_count = 0;
511                         cep->state = ST_IDLE;
512                 }
513                 return(cep);
514         }
515
516         if(aliasing)
517         {
518                 char *src_tela = "ERROR-src_tela";
519                 char *dst_tela = "ERROR-dst_tela";
520
521                 src_tela = get_alias(mp->src_telno);
522                 dst_tela = get_alias(mp->dst_telno);
523
524                 log(LL_CHD, "%05d Call from %s to %s",
525                         mp->header.cdid, src_tela, dst_tela);
526         }
527         else
528         {
529                 log(LL_CHD, "%05d <unknown> incoming call from %s to %s",
530                         mp->header.cdid, mp->src_telno, mp->dst_telno);
531         }
532         return(NULL);
533 }
534
535 /*---------------------------------------------------------------------------*
536  *      return address of ACTIVE config entry by controller and channel
537  *---------------------------------------------------------------------------*/
538 cfg_entry_t *
539 get_cep_by_cc(int ctrlr, int chan)
540 {
541         int i;
542
543         if((chan != CHAN_B1) && (chan != CHAN_B2))
544                 return(NULL);
545                 
546         for(i=0; i < nentries; i++)
547         {
548                 if((cfg_entry_tab[i].cdid != CDID_UNUSED)               &&
549                    (cfg_entry_tab[i].cdid != CDID_RESERVED)             &&
550                    (cfg_entry_tab[i].isdnchannelused == chan)           &&
551                    (cfg_entry_tab[i].isdncontrollerused == ctrlr)       &&
552                    ((ret_channel_state(ctrlr, chan)) == CHAN_RUN))
553                 {
554                         return(&cfg_entry_tab[i]);
555                 }
556         }
557         return(NULL);
558 }
559
560 /*---------------------------------------------------------------------------*
561  *      return address of config entry identified by cdid
562  *---------------------------------------------------------------------------*/
563 cfg_entry_t *
564 get_cep_by_cdid(int cdid)
565 {
566         int i;
567
568         for(i=0; i < nentries; i++)
569         {
570                 if(cfg_entry_tab[i].cdid == cdid
571                   || cfg_entry_tab[i].saved_call.cdid == cdid)
572                         return(&cfg_entry_tab[i]);
573         }
574         return(NULL);
575 }
576
577 /*---------------------------------------------------------------------------*
578  *      get name of a controller
579  *---------------------------------------------------------------------------*/
580 const char *
581 name_of_controller(int ctrl_type, int card_type)
582 {
583         static char *passive_card[] = {
584                 "Teles S0/8",
585                 "Teles S0/16",
586                 "Teles S0/16.3",
587                 "AVM A1 or Fritz!Card",
588                 "Teles S0/16.3 PnP",
589                 "Creatix S0 PnP",
590                 "USRobotics Sportster ISDN TA",
591                 "Dr. Neuhaus NICCY Go@",
592                 "Sedlbauer win speed",
593                 "Dynalink IS64PH",
594                 "ISDN Master, MasterII or Blaster",
595                 "AVM PCMCIA Fritz!Card",
596                 "ELSA QuickStep 1000pro/ISA",
597                 "ELSA QuickStep 1000pro/PCI",
598                 "Siemens I-Talk",
599                 "ELSA MicroLink ISDN/MC",
600                 "ELSA MicroLink MCall",
601                 "ITK ix1 micro",
602                 "AVM Fritz!Card PCI",
603                 "ELSA PCC-16",
604                 "AVM Fritz!Card PnP",           
605                 "Siemens I-Surf 2.0 PnP",               
606                 "Asuscom ISDNlink 128K PnP"
607         };
608
609         static char *daic_card[] = {
610                 "EICON.Diehl S",
611                 "EICON.Diehl SX/SXn",
612                 "EICON.Diehl SCOM",
613                 "EICON.Diehl QUADRO",
614         };
615
616         if(ctrl_type == CTRL_PASSIVE)
617         {
618                 int index = card_type - CARD_TYPEP_8;
619                 if (index >= 0 && index < (sizeof passive_card / sizeof passive_card[0]))
620                         return passive_card[index];
621         }
622         else if(ctrl_type == CTRL_DAIC)
623         {
624                 int index = card_type - CARD_TYPEA_DAIC_S;
625                 if (index >= 0 && index < (sizeof daic_card / sizeof daic_card[0] ))
626                         return daic_card[index];
627         }
628         else if(ctrl_type == CTRL_TINADD)
629         {
630                 return "Stollmann tina-dd";
631         }
632
633         return "unknown card type";
634 }
635  
636 /*---------------------------------------------------------------------------*
637  *      init controller state array
638  *---------------------------------------------------------------------------*/
639 void
640 init_controller(void)
641 {
642         int i;
643         int max = 1;
644         msg_ctrl_info_req_t mcir;
645         
646         for(i=0; i < max; i++)
647         {
648                 mcir.controller = i;
649                 
650                 if((ioctl(isdnfd, I4B_CTRL_INFO_REQ, &mcir)) < 0)
651                 {
652                         log(LL_ERR, "init_controller: ioctl I4B_CTRL_INFO_REQ failed: %s", strerror(errno));
653                         do_exit(1);
654                 }
655
656                 if((ncontroller = max = mcir.ncontroller) == 0)
657                 {
658                         log(LL_ERR, "init_controller: no ISDN controller found!");
659                         do_exit(1);
660                 }
661
662                 if(mcir.ctrl_type == -1 || mcir.card_type == -1)
663                 {
664                         log(LL_ERR, "init_controller: ctrl/card is invalid!");
665                         do_exit(1);
666                 }
667
668                 /* init controller tab */
669
670                 if((init_controller_state(i, mcir.ctrl_type, mcir.card_type, mcir.tei)) == ERROR)
671                 {
672                         log(LL_ERR, "init_controller: init_controller_state for controller %d failed", i);
673                         do_exit(1);
674                 }
675         }
676         DBGL(DL_RCCF, (log(LL_DBG, "init_controller: found %d ISDN controller(s)", max)));
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         };
692
693         if(drivertype >= BDRV_RBCH && drivertype <= BDRV_IBC)
694                 return(bdtab[drivertype]);
695         else
696                 return("unknown");
697 }
698
699 /*---------------------------------------------------------------------------*
700  *      process AOCD charging messages
701  *---------------------------------------------------------------------------*/
702 void
703 handle_charge(cfg_entry_t *cep)
704 {
705         time_t now = time(NULL);
706
707         if(cep->aoc_last == 0)          /* no last timestamp yet ? */
708         {
709                 cep->aoc_last = now;    /* add time stamp */
710         }
711         else if(cep->aoc_now == 0)      /* no current timestamp yet ? */
712         {
713                 cep->aoc_now = now;     /* current timestamp */
714         }
715         else
716         {
717                 cep->aoc_last = cep->aoc_now;
718                 cep->aoc_now = now;
719                 cep->aoc_diff = cep->aoc_now - cep->aoc_last;
720                 cep->aoc_valid = AOC_VALID;
721         }
722         
723 #ifdef USE_CURSES
724         if(do_fullscreen)
725                 display_charge(cep);
726 #endif
727
728 #ifdef I4B_EXTERNAL_MONITOR
729         if(do_monitor && accepted)
730                 monitor_evnt_charge(cep, cep->charge, 0);
731 #endif
732
733         if(cep->aoc_valid == AOC_VALID)
734         {
735                 if(cep->aoc_diff != cep->unitlength)
736                 {
737                         DBGL(DL_MSG, (log(LL_DBG, "handle_charge: AOCD unit length updated %d -> %d secs", cep->unitlength, cep->aoc_diff)));
738
739                         cep->unitlength = cep->aoc_diff;
740
741                         unitlen_chkupd(cep);
742                 }
743                 else
744                 {
745 #ifdef NOTDEF
746                         DBGL(DL_MSG, (log(LL_DBG, "handle_charge: AOCD unit length still %d secs", cep->unitlength)));
747 #endif
748                 }
749         }
750 }
751
752 /*---------------------------------------------------------------------------*
753  *      update kernel idle_time, earlyhup_time and unitlen_time
754  *---------------------------------------------------------------------------*/
755 void
756 unitlen_chkupd(cfg_entry_t *cep)
757 {
758         msg_timeout_upd_t tupd;
759
760         tupd.cdid = cep->cdid;
761
762         /* init the short hold data based on the shorthold algorithm type */
763         
764         switch(cep->shorthold_algorithm)
765         {
766                 case SHA_FIXU:
767                         tupd.shorthold_data.shorthold_algorithm = SHA_FIXU;
768                         tupd.shorthold_data.unitlen_time = cep->unitlength;
769                         tupd.shorthold_data.idle_time = cep->idle_time_out;
770                         tupd.shorthold_data.earlyhup_time = cep->earlyhangup;
771                         break;
772
773                 case SHA_VARU:
774                         tupd.shorthold_data.shorthold_algorithm = SHA_VARU;
775                         tupd.shorthold_data.unitlen_time = cep->unitlength;
776                         tupd.shorthold_data.idle_time = cep->idle_time_out;
777                         tupd.shorthold_data.earlyhup_time = 0;
778                         break;
779                 default:
780                         log(LL_ERR, "unitlen_chkupd bad shorthold_algorithm %d", cep->shorthold_algorithm );
781                         return;
782                         break;                  
783         }
784
785         if((ioctl(isdnfd, I4B_TIMEOUT_UPD, &tupd)) < 0)
786         {
787                 log(LL_ERR, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno));
788                 do_exit(1);
789         }
790 }
791
792 /*--------------------------------------------------------------------------*
793  *      this is intended to be called by do_exit and closes down all
794  *      active connections before the daemon exits or is reconfigured.
795  *--------------------------------------------------------------------------*/
796 void
797 close_allactive(void)
798 {
799         int i, j;
800         cfg_entry_t *cep = NULL;
801
802         j = 0;
803         
804         for (i = 0; i < ncontroller; i++)
805         {
806                 if((get_controller_state(i)) != CTRL_UP)
807                         continue;
808
809                 if((ret_channel_state(i, CHAN_B1)) == CHAN_RUN)
810                 {
811                         if((cep = get_cep_by_cc(i, CHAN_B1)) != NULL)
812                         {
813 #ifdef USE_CURSES
814                                 if(do_fullscreen)
815                                         display_disconnect(cep);
816 #endif
817 #ifdef I4B_EXTERNAL_MONITOR
818                                 monitor_evnt_disconnect(cep);
819 #endif
820                                 next_state(cep, EV_DRQ);
821                                 j++;
822                         }
823                 }
824
825                 if((ret_channel_state(i, CHAN_B2)) == CHAN_RUN)
826                 {
827                         if((cep = get_cep_by_cc(i, CHAN_B2)) != NULL)
828                         {
829 #ifdef USE_CURSES
830                                 if(do_fullscreen)
831                                         display_disconnect(cep);
832 #endif
833 #ifdef I4B_EXTERNAL_MONITOR
834                                 monitor_evnt_disconnect(cep);
835 #endif
836                                 next_state(cep, EV_DRQ);
837                                 j++;                            
838                         }
839                 }
840         }
841
842         if(j)
843         {
844                 log(LL_DMN, "close_allactive: waiting for all connections terminated");
845                 sleep(5);
846         }
847 }
848
849 /*--------------------------------------------------------------------------*
850  *      set an interface up
851  *--------------------------------------------------------------------------*/
852 void
853 if_up(cfg_entry_t *cep)
854 {
855         msg_updown_ind_t mui;
856                         
857         /* set interface up */
858         
859         DBGL(DL_MSG, (log(LL_DBG, "if_up: taking %s%d up", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
860         
861         mui.driver = cep->usrdevicename;
862         mui.driver_unit = cep->usrdeviceunit;
863         mui.updown = SOFT_ENA;
864                         
865         if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
866         {
867                 log(LL_ERR, "if_up: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
868                 do_exit(1);
869         }
870         cep->down_retry_count = 0;
871
872 #ifdef USE_CURSES
873         if(do_fullscreen)
874                 display_updown(cep, 1);
875 #endif
876 #ifdef I4B_EXTERNAL_MONITOR
877         monitor_evnt_updown(cep, 1);
878 #endif
879         
880 }
881
882 /*--------------------------------------------------------------------------*
883  *      set an interface down
884  *--------------------------------------------------------------------------*/
885 void
886 if_down(cfg_entry_t *cep)
887 {
888         msg_updown_ind_t mui;
889                         
890         /* set interface up */
891         
892         DBGL(DL_MSG, (log(LL_DBG, "if_down: taking %s%d down", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
893         
894         mui.driver = cep->usrdevicename;
895         mui.driver_unit = cep->usrdeviceunit;
896         mui.updown = SOFT_DIS;
897                         
898         if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
899         {
900                 log(LL_ERR, "if_down: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
901                 do_exit(1);
902         }
903         cep->went_down_time = time(NULL);
904         cep->down_retry_count = 0;
905
906 #ifdef USE_CURSES
907         if(do_fullscreen)
908                 display_updown(cep, 0);
909 #endif
910 #ifdef I4B_EXTERNAL_MONITOR
911         monitor_evnt_updown(cep, 0);
912 #endif
913
914 }
915
916 /*--------------------------------------------------------------------------*
917  *      send a dial response to (an interface in) the kernel 
918  *--------------------------------------------------------------------------*/
919 void
920 dialresponse(cfg_entry_t *cep, int dstat)
921 {
922         msg_dialout_resp_t mdr;
923
924         static char *stattab[] = {
925                 "normal condition",
926                 "temporary failure",
927                 "permanent failure",
928                 "dialout not allowed"
929         };
930
931         if(dstat < DSTAT_NONE || dstat > DSTAT_INONLY)
932         {
933                 log(LL_ERR, "dialresponse: dstat out of range %d!", dstat);
934                 return;
935         }
936         
937         mdr.driver = cep->usrdevicename;
938         mdr.driver_unit = cep->usrdeviceunit;
939         mdr.stat = dstat;
940         mdr.cause = cep->disc_cause;    
941         
942         if((ioctl(isdnfd, I4B_DIALOUT_RESP, &mdr)) < 0)
943         {
944                 log(LL_ERR, "dialresponse: ioctl I4B_DIALOUT_RESP failed: %s", strerror(errno));
945                 do_exit(1);
946         }
947
948         DBGL(DL_DRVR, (log(LL_DBG, "dialresponse: sent [%s]", stattab[dstat])));
949 }
950 /* EOF */
951