Merge branch 'vendor/ACPICA-UNIX'
[dragonfly.git] / sys / net / i4b / layer4 / i4b_l4.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_l4.c - kernel interface to userland
28  *      -----------------------------------------
29  *
30  *      $Id: i4b_l4.c,v 1.54 2000/08/28 07:24:59 hm Exp $ 
31  *
32  * $FreeBSD: src/sys/i4b/layer4/i4b_l4.c,v 1.6.2.2 2001/12/16 15:12:59 hm Exp $
33  * $DragonFly: src/sys/net/i4b/layer4/i4b_l4.c,v 1.7 2005/06/14 21:19:19 joerg Exp $
34  *
35  *      last edit-date: [Sun Aug 27 14:53:42 2000]
36  *
37  *---------------------------------------------------------------------------*/
38
39 #include "use_i4b.h"
40 #include "use_i4bipr.h"
41
42 #if NI4B > 0
43
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/systm.h>
47 #include <sys/mbuf.h>
48 #include <sys/thread2.h>
49
50 #include "use_i4bing.h"
51 #include "use_i4bisppp.h"
52 #include "use_i4brbch.h"
53 #include "use_i4btel.h"
54
55 #include <net/i4b/include/machine/i4b_debug.h>
56 #include <net/i4b/include/machine/i4b_ioctl.h>
57 #include <net/i4b/include/machine/i4b_cause.h>
58
59 #include "../include/i4b_global.h"
60 #include "../include/i4b_l3l4.h"
61 #include "../include/i4b_mbuf.h"
62 #include "i4b_l4.h"
63
64 unsigned int i4b_l4_debug = L4_DEBUG_DEFAULT;
65
66 struct ctrl_type_desc ctrl_types[CTRL_NUMTYPES] = { { NULL, NULL} };
67
68 static int i4b_link_bchandrvr(call_desc_t *cd);
69 static void i4b_unlink_bchandrvr(call_desc_t *cd);
70 static void i4b_l4_setup_timeout(call_desc_t *cd);
71 static void i4b_idle_check_fix_unit(call_desc_t *cd);
72 static void i4b_idle_check_var_unit(call_desc_t *cd);
73 static void i4b_l4_setup_timeout_fix_unit(call_desc_t *cd);
74 static void i4b_l4_setup_timeout_var_unit(call_desc_t *cd);
75 static time_t i4b_get_idletime(call_desc_t *cd);
76 #if NI4BISPPP > 0
77 extern time_t i4bisppp_idletime(int);
78 #endif
79
80 /*---------------------------------------------------------------------------*
81  *      send MSG_PDEACT_IND message to userland
82  *---------------------------------------------------------------------------*/
83 void
84 i4b_l4_pdeact(int controller, int numactive)
85 {
86         struct mbuf *m;
87         int i;
88         call_desc_t *cd;
89         
90         for(i=0; i < N_CALL_DESC; i++)
91         {
92                 if((call_desc[i].cdid != CDID_UNUSED)                             &&
93                    (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) &&
94                    (ctrl_desc[call_desc[i].controller].unit == controller))
95                 {
96                         cd = &call_desc[i];
97                         
98                         if(cd->timeout_active)
99                         {
100                                 callout_stop(&cd->idle_timeout);
101                         }
102                         
103                         if(cd->dlt != NULL)
104                         {
105                                 (*cd->dlt->line_disconnected)(cd->driver_unit, (void *)cd);
106                                 i4b_unlink_bchandrvr(cd);
107                         }
108                 
109                         if((cd->channelid >= 0) & (cd->channelid < ctrl_desc[cd->controller].nbch))
110                         {
111                                 ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE;
112                         }
113
114                         cd->cdid = CDID_UNUSED;
115                 }
116         }
117         
118         if((m = i4b_Dgetmbuf(sizeof(msg_pdeact_ind_t))) != NULL)
119         {
120                 msg_pdeact_ind_t *md = (msg_pdeact_ind_t *)m->m_data;
121
122                 md->header.type = MSG_PDEACT_IND;
123                 md->header.cdid = -1;
124
125                 md->controller = controller;
126                 md->numactive = numactive;
127
128                 i4bputqueue_hipri(m);           /* URGENT !!! */
129         }
130 }
131
132 /*---------------------------------------------------------------------------*
133  *      send MSG_L12STAT_IND message to userland
134  *---------------------------------------------------------------------------*/
135 void
136 i4b_l4_l12stat(int controller, int layer, int state)
137 {
138         struct mbuf *m;
139
140         if((m = i4b_Dgetmbuf(sizeof(msg_l12stat_ind_t))) != NULL)
141         {
142                 msg_l12stat_ind_t *md = (msg_l12stat_ind_t *)m->m_data;
143
144                 md->header.type = MSG_L12STAT_IND;
145                 md->header.cdid = -1;
146
147                 md->controller = controller;
148                 md->layer = layer;
149                 md->state = state;
150
151                 i4bputqueue(m);
152         }
153 }
154
155 /*---------------------------------------------------------------------------*
156  *      send MSG_TEIASG_IND message to userland
157  *---------------------------------------------------------------------------*/
158 void
159 i4b_l4_teiasg(int controller, int tei)
160 {
161         struct mbuf *m;
162
163         if((m = i4b_Dgetmbuf(sizeof(msg_teiasg_ind_t))) != NULL)
164         {
165                 msg_teiasg_ind_t *md = (msg_teiasg_ind_t *)m->m_data;
166
167                 md->header.type = MSG_TEIASG_IND;
168                 md->header.cdid = -1;
169
170                 md->controller = controller;
171                 md->tei = ctrl_desc[controller].tei;
172
173                 i4bputqueue(m);
174         }
175 }
176
177 /*---------------------------------------------------------------------------*
178  *      send MSG_DIALOUT_IND message to userland
179  *---------------------------------------------------------------------------*/
180 void
181 i4b_l4_dialout(int driver, int driver_unit)
182 {
183         struct mbuf *m;
184
185         if((m = i4b_Dgetmbuf(sizeof(msg_dialout_ind_t))) != NULL)
186         {
187                 msg_dialout_ind_t *md = (msg_dialout_ind_t *)m->m_data;
188
189                 md->header.type = MSG_DIALOUT_IND;
190                 md->header.cdid = -1;
191
192                 md->driver = driver;
193                 md->driver_unit = driver_unit;  
194
195                 i4bputqueue(m);
196         }
197 }
198
199 /*---------------------------------------------------------------------------*
200  *      send MSG_DIALOUTNUMBER_IND message to userland
201  *---------------------------------------------------------------------------*/
202 void
203 i4b_l4_dialoutnumber(int driver, int driver_unit, int cmdlen, char *cmd)
204 {
205         struct mbuf *m;
206
207         if((m = i4b_Dgetmbuf(sizeof(msg_dialoutnumber_ind_t))) != NULL)
208         {
209                 msg_dialoutnumber_ind_t *md = (msg_dialoutnumber_ind_t *)m->m_data;
210
211                 md->header.type = MSG_DIALOUTNUMBER_IND;
212                 md->header.cdid = -1;
213
214                 md->driver = driver;
215                 md->driver_unit = driver_unit;
216
217                 if(cmdlen > TELNO_MAX)
218                         cmdlen = TELNO_MAX;
219
220                 md->cmdlen = cmdlen;
221                 bcopy(cmd, md->cmd, cmdlen);
222                 i4bputqueue(m);
223         }
224 }
225
226 /*---------------------------------------------------------------------------*
227  *      send MSG_KEYPAD_IND message to userland
228  *---------------------------------------------------------------------------*/
229 void
230 i4b_l4_keypad(int driver, int driver_unit, int cmdlen, char *cmd)
231 {
232         struct mbuf *m;
233
234         if((m = i4b_Dgetmbuf(sizeof(msg_keypad_ind_t))) != NULL)
235         {
236                 msg_keypad_ind_t *md = (msg_keypad_ind_t *)m->m_data;
237
238                 md->header.type = MSG_KEYPAD_IND;
239                 md->header.cdid = -1;
240
241                 md->driver = driver;
242                 md->driver_unit = driver_unit;
243
244                 if(cmdlen > KEYPAD_MAX)
245                         cmdlen = KEYPAD_MAX;
246
247                 md->cmdlen = cmdlen;
248                 bcopy(cmd, md->cmd, cmdlen);
249                 i4bputqueue(m);
250         }
251 }
252
253 /*---------------------------------------------------------------------------*
254  *      send MSG_NEGOTIATION_COMPL message to userland
255  *---------------------------------------------------------------------------*/
256 void
257 i4b_l4_negcomplete(call_desc_t *cd)
258 {
259         struct mbuf *m;
260
261         if((m = i4b_Dgetmbuf(sizeof(msg_negcomplete_ind_t))) != NULL)
262         {
263                 msg_negcomplete_ind_t *md = (msg_negcomplete_ind_t *)m->m_data;
264
265                 md->header.type = MSG_NEGCOMP_IND;
266                 md->header.cdid = cd->cdid;
267
268                 i4bputqueue(m);
269         }
270 }
271
272 /*---------------------------------------------------------------------------*
273  *      send MSG_IFSTATE_CHANGED_IND message to userland
274  *---------------------------------------------------------------------------*/
275 void
276 i4b_l4_ifstate_changed(call_desc_t *cd, int new_state)
277 {
278         struct mbuf *m;
279
280         if((m = i4b_Dgetmbuf(sizeof(msg_ifstatechg_ind_t))) != NULL)
281         {
282                 msg_ifstatechg_ind_t *md = (msg_ifstatechg_ind_t *)m->m_data;
283
284                 md->header.type = MSG_IFSTATE_CHANGED_IND;
285                 md->header.cdid = cd->cdid;
286                 md->state = new_state;
287
288                 i4bputqueue(m);
289         }
290 }
291
292 /*---------------------------------------------------------------------------*
293  *      send MSG_DRVRDISC_REQ message to userland
294  *---------------------------------------------------------------------------*/
295 void
296 i4b_l4_drvrdisc(int driver, int driver_unit)
297 {
298         struct mbuf *m;
299
300         if((m = i4b_Dgetmbuf(sizeof(msg_drvrdisc_req_t))) != NULL)
301         {
302                 msg_drvrdisc_req_t *md = (msg_drvrdisc_req_t *)m->m_data;
303
304                 md->header.type = MSG_DRVRDISC_REQ;
305                 md->header.cdid = -1;
306
307                 md->driver = driver;
308                 md->driver_unit = driver_unit;  
309
310                 i4bputqueue(m);
311         }
312 }
313
314 /*---------------------------------------------------------------------------*
315  *      send MSG_ACCT_IND message to userland
316  *---------------------------------------------------------------------------*/
317 void
318 i4b_l4_accounting(int driver, int driver_unit, int accttype, int ioutbytes,
319                 int iinbytes, int ro, int ri, int outbytes, int inbytes)
320 {
321         struct mbuf *m;
322
323         if((m = i4b_Dgetmbuf(sizeof(msg_accounting_ind_t))) != NULL)
324         {
325                 msg_accounting_ind_t *md = (msg_accounting_ind_t *)m->m_data;
326
327                 md->header.type = MSG_ACCT_IND;
328                 md->header.cdid = -1;
329
330                 md->driver = driver;
331                 md->driver_unit = driver_unit;  
332
333                 md->accttype = accttype;
334                 md->ioutbytes = ioutbytes;
335                 md->iinbytes = iinbytes;
336                 md->outbps = ro;
337                 md->inbps = ri;
338                 md->outbytes = outbytes;
339                 md->inbytes = inbytes;
340                 
341                 i4bputqueue(m);
342         }
343 }
344
345 /*---------------------------------------------------------------------------*
346  *      send MSG_CONNECT_IND message to userland
347  *---------------------------------------------------------------------------*/
348 void
349 i4b_l4_connect_ind(call_desc_t *cd)
350 {
351         struct mbuf *m;
352
353         if((m = i4b_Dgetmbuf(sizeof(msg_connect_ind_t))) != NULL)
354         {
355                 msg_connect_ind_t *mp = (msg_connect_ind_t *)m->m_data;
356
357                 mp->header.type = MSG_CONNECT_IND;
358                 mp->header.cdid = cd->cdid;
359
360                 mp->controller = cd->controller;
361                 mp->channel = cd->channelid;
362                 mp->bprot = cd->bprot;
363
364                 cd->dir = DIR_INCOMING;
365
366                 if(strlen(cd->dst_telno) > 0)
367                         strcpy(mp->dst_telno, cd->dst_telno);
368                 else
369                         strcpy(mp->dst_telno, TELNO_EMPTY);
370
371                 if(strlen(cd->src_telno) > 0)
372                         strcpy(mp->src_telno, cd->src_telno);
373                 else
374                         strcpy(mp->src_telno, TELNO_EMPTY);
375                         
376                 strcpy(mp->display, cd->display);
377
378                 mp->scr_ind = cd->scr_ind;
379                 mp->prs_ind = cd->prs_ind;              
380                 
381                 T400_start(cd);
382                 
383                 i4bputqueue(m);
384         }
385 }
386
387 /*---------------------------------------------------------------------------*
388  *      send MSG_CONNECT_ACTIVE_IND message to userland
389  *---------------------------------------------------------------------------*/
390 void
391 i4b_l4_connect_active_ind(call_desc_t *cd)
392 {
393         struct mbuf *m;
394
395         crit_enter();
396
397         cd->last_active_time = cd->connect_time = SECOND;
398
399         NDBGL4(L4_TIMO, "last_active/connect_time=%ld", (long)cd->connect_time);
400         
401         i4b_link_bchandrvr(cd);
402
403         (*cd->dlt->line_connected)(cd->driver_unit, (void *)cd);
404
405         i4b_l4_setup_timeout(cd);
406         
407         crit_exit();
408         
409         if((m = i4b_Dgetmbuf(sizeof(msg_connect_active_ind_t))) != NULL)
410         {
411                 msg_connect_active_ind_t *mp = (msg_connect_active_ind_t *)m->m_data;
412
413                 mp->header.type = MSG_CONNECT_ACTIVE_IND;
414                 mp->header.cdid = cd->cdid;
415                 mp->controller = cd->controller;
416                 mp->channel = cd->channelid;
417                 if(cd->datetime[0] != '\0')
418                         strcpy(mp->datetime, cd->datetime);
419                 else
420                         mp->datetime[0] = '\0';
421                 i4bputqueue(m);
422         }
423 }
424
425 /*---------------------------------------------------------------------------*
426  *      send MSG_DISCONNECT_IND message to userland
427  *---------------------------------------------------------------------------*/
428 void
429 i4b_l4_disconnect_ind(call_desc_t *cd)
430 {
431         struct mbuf *m;
432
433         if(cd->timeout_active)
434                 callout_stop(&cd->idle_timeout);
435
436         if(cd->dlt != NULL)
437         {
438                 (*cd->dlt->line_disconnected)(cd->driver_unit, (void *)cd);
439                 i4b_unlink_bchandrvr(cd);
440         }
441
442         if((cd->channelid >= 0) && (cd->channelid < ctrl_desc[cd->controller].nbch))
443         {
444                 ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE;
445         }
446         else
447         {
448                 /* no error, might be hunting call for callback */
449                 NDBGL4(L4_MSG, "channel free not valid but %d!", cd->channelid);
450         }
451         
452         if((m = i4b_Dgetmbuf(sizeof(msg_disconnect_ind_t))) != NULL)
453         {
454                 msg_disconnect_ind_t *mp = (msg_disconnect_ind_t *)m->m_data;
455
456                 mp->header.type = MSG_DISCONNECT_IND;
457                 mp->header.cdid = cd->cdid;
458                 mp->cause = cd->cause_in;
459
460                 i4bputqueue(m);
461         }
462 }
463
464 /*---------------------------------------------------------------------------*
465  *      send MSG_IDLE_TIMEOUT_IND message to userland
466  *---------------------------------------------------------------------------*/
467 void
468 i4b_l4_idle_timeout_ind(call_desc_t *cd)
469 {
470         struct mbuf *m;
471
472         if((m = i4b_Dgetmbuf(sizeof(msg_idle_timeout_ind_t))) != NULL)
473         {
474                 msg_idle_timeout_ind_t *mp = (msg_idle_timeout_ind_t *)m->m_data;
475
476                 mp->header.type = MSG_IDLE_TIMEOUT_IND;
477                 mp->header.cdid = cd->cdid;
478
479                 i4bputqueue(m);
480         }
481 }
482
483 /*---------------------------------------------------------------------------*
484  *      send MSG_CHARGING_IND message to userland
485  *---------------------------------------------------------------------------*/
486 void
487 i4b_l4_charging_ind(call_desc_t *cd)
488 {
489         struct mbuf *m;
490
491         if((m = i4b_Dgetmbuf(sizeof(msg_charging_ind_t))) != NULL)
492         {
493                 msg_charging_ind_t *mp = (msg_charging_ind_t *)m->m_data;
494
495                 mp->header.type = MSG_CHARGING_IND;
496                 mp->header.cdid = cd->cdid;
497                 mp->units_type = cd->units_type;
498
499 /*XXX*/         if(mp->units_type == CHARGE_CALC)
500                         mp->units = cd->cunits;
501                 else
502                         mp->units = cd->units;
503
504                 i4bputqueue(m);
505         }
506 }
507
508 /*---------------------------------------------------------------------------*
509  *      send MSG_STATUS_IND message to userland
510  *---------------------------------------------------------------------------*/
511 void
512 i4b_l4_status_ind(call_desc_t *cd)
513 {
514 }
515
516 /*---------------------------------------------------------------------------*
517  *      send MSG_ALERT_IND message to userland
518  *---------------------------------------------------------------------------*/
519 void
520 i4b_l4_alert_ind(call_desc_t *cd)
521 {
522         struct mbuf *m;
523
524         if((m = i4b_Dgetmbuf(sizeof(msg_alert_ind_t))) != NULL)
525         {
526                 msg_alert_ind_t *mp = (msg_alert_ind_t *)m->m_data;
527
528                 mp->header.type = MSG_ALERT_IND;
529                 mp->header.cdid = cd->cdid;
530
531                 i4bputqueue(m);
532         }
533 }
534
535 /*---------------------------------------------------------------------------*
536  *      send MSG_INFO_IND message to userland
537  *---------------------------------------------------------------------------*/
538 void
539 i4b_l4_info_ind(call_desc_t *cd)
540 {
541 }
542
543 /*---------------------------------------------------------------------------*
544  *      send MSG_INFO_IND message to userland
545  *---------------------------------------------------------------------------*/
546 void
547 i4b_l4_proceeding_ind(call_desc_t *cd)
548 {
549         struct mbuf *m;
550
551         if((m = i4b_Dgetmbuf(sizeof(msg_proceeding_ind_t))) != NULL)
552         {
553                 msg_proceeding_ind_t *mp = (msg_proceeding_ind_t *)m->m_data;
554
555                 mp->header.type = MSG_PROCEEDING_IND;
556                 mp->header.cdid = cd->cdid;
557                 mp->controller = cd->controller;
558                 mp->channel = cd->channelid;
559                 i4bputqueue(m);
560         }
561 }
562
563 /*---------------------------------------------------------------------------*
564  *    send MSG_PACKET_IND message to userland
565  *---------------------------------------------------------------------------*/
566 void
567 i4b_l4_packet_ind(int driver, int driver_unit, int dir, struct mbuf *pkt)
568 {
569         struct mbuf *m;
570         int len = pkt->m_pkthdr.len;
571         unsigned char *ip = pkt->m_data;
572
573         if((m = i4b_Dgetmbuf(sizeof(msg_packet_ind_t))) != NULL)
574         {
575                 msg_packet_ind_t *mp = (msg_packet_ind_t *)m->m_data;
576
577                 mp->header.type = MSG_PACKET_IND;
578                 mp->header.cdid = -1;
579                 mp->driver = driver;
580                 mp->driver_unit = driver_unit;
581                 mp->direction = dir;
582                 memcpy(mp->pktdata, ip,
583                         len <MAX_PACKET_LOG ? len : MAX_PACKET_LOG);
584                 i4bputqueue(m);
585         }
586 }
587
588 /*---------------------------------------------------------------------------*
589  *      link a driver(unit) to a B-channel(controller,unit,channel)
590  *---------------------------------------------------------------------------*/
591 static int
592 i4b_link_bchandrvr(call_desc_t *cd)
593 {
594         int t = ctrl_desc[cd->controller].ctrl_type;
595         
596         if(t < 0 || t >= CTRL_NUMTYPES || ctrl_types[t].get_linktab == NULL)
597         {
598                         cd->ilt = NULL;
599         }
600         else
601         {
602                 cd->ilt = ctrl_types[t].get_linktab(
603                         ctrl_desc[cd->controller].unit,
604                         cd->channelid);
605         }
606
607         switch(cd->driver)
608         {
609 #if NI4BRBCH > 0
610                 case BDRV_RBCH:
611                         cd->dlt = rbch_ret_linktab(cd->driver_unit);
612                         break;
613 #endif
614                 
615 #if NI4BTEL > 0
616                 case BDRV_TEL:
617                         cd->dlt = tel_ret_linktab(cd->driver_unit);
618                         break;
619 #endif
620
621 #if NI4BIPR > 0
622                 case BDRV_IPR:
623                         cd->dlt = ipr_ret_linktab(cd->driver_unit);
624                         break;
625 #endif
626
627 #if NI4BISPPP > 0
628                 case BDRV_ISPPP:
629                         cd->dlt = i4bisppp_ret_linktab(cd->driver_unit);
630                         break;
631 #endif
632
633 #if NI4BING > 0
634                 case BDRV_ING:
635                         cd->dlt = ing_ret_linktab(cd->driver_unit);
636                         break;
637 #endif
638
639                 default:
640                         cd->dlt = NULL;
641                         break;
642         }
643
644         if(cd->dlt == NULL || cd->ilt == NULL)
645                 return(-1);
646
647         if(t >= 0 && t < CTRL_NUMTYPES && ctrl_types[t].set_linktab != NULL)
648         {
649                 ctrl_types[t].set_linktab(
650                                 ctrl_desc[cd->controller].unit,
651                                 cd->channelid,
652                                 cd->dlt);
653         }
654
655         switch(cd->driver)
656         {
657 #if NI4BRBCH > 0
658                 case BDRV_RBCH:
659                         rbch_set_linktab(cd->driver_unit, cd->ilt);
660                         break;
661 #endif
662
663 #if NI4BTEL > 0
664                 case BDRV_TEL:
665                         tel_set_linktab(cd->driver_unit, cd->ilt);
666                         break;
667 #endif
668
669 #if NI4BIPR > 0
670                 case BDRV_IPR:
671                         ipr_set_linktab(cd->driver_unit, cd->ilt);
672                         break;
673 #endif
674
675 #if NI4BISPPP > 0
676                 case BDRV_ISPPP:
677                         i4bisppp_set_linktab(cd->driver_unit, cd->ilt);
678                         break;
679 #endif
680
681 #if NI4BING > 0
682                 case BDRV_ING:
683                         ing_set_linktab(cd->driver_unit, cd->ilt);
684                         break;
685 #endif
686
687                 default:
688                         return(0);
689                         break;
690         }
691
692         /* activate B channel */
693                 
694         (*cd->ilt->bch_config)(cd->ilt->unit, cd->ilt->channel, cd->bprot, 1);
695
696         return(0);
697 }
698
699 /*---------------------------------------------------------------------------*
700  *      unlink a driver(unit) from a B-channel(controller,unit,channel)
701  *---------------------------------------------------------------------------*/
702 static void
703 i4b_unlink_bchandrvr(call_desc_t *cd)
704 {
705         int t = ctrl_desc[cd->controller].ctrl_type;
706
707         if(t < 0 || t >= CTRL_NUMTYPES || ctrl_types[t].get_linktab == NULL)
708         {
709                 cd->ilt = NULL;
710                 return;
711         }
712         else
713         {
714                 cd->ilt = ctrl_types[t].get_linktab(
715                                 ctrl_desc[cd->controller].unit,
716                                 cd->channelid);
717         }
718         
719         /* deactivate B channel */
720                 
721         (*cd->ilt->bch_config)(cd->ilt->unit, cd->ilt->channel, cd->bprot, 0);
722
723
724 /*---------------------------------------------------------------------------
725
726         How shorthold mode works for OUTGOING connections
727         =================================================
728
729         |<---- unchecked-window ------->|<-checkwindow->|<-safetywindow>|
730
731 idletime_state:      IST_NONCHK             IST_CHECK       IST_SAFE    
732         
733         |                               |               |               |
734   time>>+-------------------------------+---------------+---------------+-...
735         |                               |               |               |
736         |                               |<--idle_time-->|<--earlyhup--->|
737         |<-----------------------unitlen------------------------------->|
738
739         
740           unitlen - specifies the time a charging unit lasts
741         idle_time - specifies the thime the line must be idle at the
742                     end of the unit to be elected for hangup
743          earlyhup - is the beginning of a timing safety zone before the
744                     next charging unit starts
745
746         The algorithm works as follows: lets assume the unitlen is 100
747         secons, idle_time is 40 seconds and earlyhup is 10 seconds.
748         The line then must be idle 50 seconds after the begin of the
749         current unit and it must then be quiet for 40 seconds. if it
750         has been quiet for this 40 seconds, the line is closed 10
751         seconds before the next charging unit starts. In case there was
752         any traffic within the idle_time, the line is not closed.
753         It does not matter whether there was any traffic between second
754         0 and second 50 or not.
755
756
757         How shorthold mode works for INCOMING connections
758         =================================================
759
760         it is just possible to specify a maximum idle time for incoming
761         connections, after this time of no activity on the line the line
762         is closed.
763         
764 ---------------------------------------------------------------------------*/   
765
766 static time_t
767 i4b_get_idletime(call_desc_t *cd)
768 {
769         switch (cd->driver) {
770 #if NI4BISPPP > 0
771                 case BDRV_ISPPP:
772                         return i4bisppp_idletime(cd->driver_unit);
773                 break;
774 #endif
775                 default:
776                         return cd->last_active_time;
777                 break;
778         }
779 }
780 /*---------------------------------------------------------------------------*
781  *      B channel idle check timeout setup
782  *---------------------------------------------------------------------------*/ 
783 static void
784 i4b_l4_setup_timeout(call_desc_t *cd)
785 {
786         NDBGL4(L4_TIMO, "%ld: direction %d, shorthold algorithm %d",
787                 (long)SECOND, cd->dir, cd->shorthold_data.shorthold_algorithm);
788         
789         cd->timeout_active = 0;
790         cd->idletime_state = IST_IDLE;
791         
792         if((cd->dir == DIR_INCOMING) && (cd->max_idle_time > 0))
793         {
794                 /* incoming call: simple max idletime check */
795         
796                 callout_reset(&cd->idle_timeout, hz / 2,
797                                 (void *)i4b_idle_check, cd);
798                 cd->timeout_active = 1;
799                 NDBGL4(L4_TIMO, "%ld: incoming-call, setup max_idle_time to %ld", (long)SECOND, (long)cd->max_idle_time);
800         }
801         else if((cd->dir == DIR_OUTGOING) && (cd->shorthold_data.idle_time > 0))
802         {
803                 switch( cd->shorthold_data.shorthold_algorithm )
804                 {
805                         default:        /* fall into the old fix algorithm */
806                         case SHA_FIXU:
807                                 i4b_l4_setup_timeout_fix_unit( cd );
808                                 break;
809                                 
810                         case SHA_VARU:
811                                 i4b_l4_setup_timeout_var_unit( cd );
812                                 break;
813                 }
814         }
815         else
816         {
817                 NDBGL4(L4_TIMO, "no idle_timeout configured");
818         }
819 }
820
821 /*---------------------------------------------------------------------------*
822  *      fixed unit algorithm B channel idle check timeout setup
823  *---------------------------------------------------------------------------*/
824 static void
825 i4b_l4_setup_timeout_fix_unit(call_desc_t *cd)
826 {
827         /* outgoing call */
828         
829         if((cd->shorthold_data.idle_time > 0) && (cd->shorthold_data.unitlen_time == 0))
830         {
831                 /* outgoing call: simple max idletime check */
832                 
833                 callout_reset(&cd->idle_timeout, hz / 2,
834                                 (void *)i4b_idle_check, cd);
835                 cd->timeout_active = 1;
836                 NDBGL4(L4_TIMO, "%ld: outgoing-call, setup idle_time to %ld",
837                         (long)SECOND, (long)cd->shorthold_data.idle_time);
838         }
839         else if((cd->shorthold_data.unitlen_time > 0) && (cd->shorthold_data.unitlen_time > (cd->shorthold_data.idle_time + cd->shorthold_data.earlyhup_time)))
840         {
841                 /* outgoing call: full shorthold mode check */
842                 
843                 callout_reset(&cd->idle_timeout, 
844                         hz * (cd->shorthold_data.unitlen_time - 
845                           (cd->shorthold_data.idle_time + 
846                           cd->shorthold_data.earlyhup_time)),
847                         (void *)i4b_idle_check, cd);
848                 cd->timeout_active = 1;
849                 cd->idletime_state = IST_NONCHK;
850                 NDBGL4(L4_TIMO, "%ld: outgoing-call, start %ld sec nocheck window", 
851                         (long)SECOND, (long)(cd->shorthold_data.unitlen_time - (cd->shorthold_data.idle_time + cd->shorthold_data.earlyhup_time)));
852
853                 if(cd->aocd_flag == 0)
854                 {
855                         cd->units_type = CHARGE_CALC;
856                         cd->cunits++;
857                         i4b_l4_charging_ind(cd);
858                 }
859         }
860         else
861         {
862                 /* parms somehow got wrong .. */
863                 
864                 NDBGL4(L4_ERR, "%ld: ERROR: idletime[%ld]+earlyhup[%ld] > unitlength[%ld]!",
865                         (long)SECOND, (long)cd->shorthold_data.idle_time, (long)cd->shorthold_data.earlyhup_time, (long)cd->shorthold_data.unitlen_time);
866         }
867 }
868
869 /*---------------------------------------------------------------------------*
870  *      variable unit algorithm B channel idle check timeout setup
871  *---------------------------------------------------------------------------*/
872 static void
873 i4b_l4_setup_timeout_var_unit(call_desc_t *cd)
874 {
875         /* outgoing call: variable unit idletime check */
876                 
877         /*
878          * start checking for an idle connect one second before the end of the unit.
879          * The one second takes into account of rounding due to the driver only
880          * using the seconds and not the uSeconds of the current time
881          */
882         cd->idletime_state = IST_CHECK; /* move directly to the checking state */
883
884         callout_reset(&cd->idle_timeout, 
885                         hz * (cd->shorthold_data.unitlen_time - 1),
886                         (void *)i4b_idle_check, cd);
887         cd->timeout_active = 1;
888         NDBGL4(L4_TIMO, "%ld: outgoing-call, var idle time - setup to %ld",
889                 (long)SECOND, (long)cd->shorthold_data.unitlen_time);
890 }
891
892
893 /*---------------------------------------------------------------------------*
894  *      B channel idle check timeout function
895  *---------------------------------------------------------------------------*/ 
896 void
897 i4b_idle_check(call_desc_t *cd)
898 {
899         if(cd->cdid == CDID_UNUSED)
900                 return;
901         
902         crit_enter();
903
904         /* failsafe */
905
906         if(cd->timeout_active == 0)
907         {
908                 NDBGL4(L4_ERR, "ERROR: timeout_active == 0 !!!");
909         }
910         else
911         {       
912                 cd->timeout_active = 0;
913         }
914         
915         /* incoming connections, simple idletime check */
916
917         if(cd->dir == DIR_INCOMING)
918         {
919                 if((i4b_get_idletime(cd) + cd->max_idle_time) <= SECOND)
920                 {
921                         NDBGL4(L4_TIMO, "%ld: incoming-call, line idle timeout, disconnecting!", (long)SECOND);
922                         (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid,
923                                         (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
924                         i4b_l4_idle_timeout_ind(cd);
925                 }
926                 else
927                 {
928                         NDBGL4(L4_TIMO, "%ld: incoming-call, activity, last_active=%ld, max_idle=%ld", (long)SECOND, (long)i4b_get_idletime(cd), (long)cd->max_idle_time);
929
930                         callout_reset(&cd->idle_timeout, hz / 2,
931                                         (void *)i4b_idle_check, cd);
932                         cd->timeout_active = 1;
933                 }
934         }
935
936         /* outgoing connections */
937
938         else if(cd->dir == DIR_OUTGOING)
939         {
940                 switch( cd->shorthold_data.shorthold_algorithm )
941                 {
942                         case SHA_FIXU:
943                                 i4b_idle_check_fix_unit( cd );
944                                 break;
945                         case SHA_VARU:
946                                 i4b_idle_check_var_unit( cd );
947                                 break;
948                         default:
949                                 NDBGL4(L4_TIMO, "%ld: bad value for shorthold_algorithm of %d",
950                                         (long)SECOND, cd->shorthold_data.shorthold_algorithm);
951                                 i4b_idle_check_fix_unit( cd );
952                                 break;
953                 }
954         }
955         crit_exit();
956 }
957
958 /*---------------------------------------------------------------------------*
959  *      fixed unit algorithm B channel idle check timeout function
960  *---------------------------------------------------------------------------*/
961 static void
962 i4b_idle_check_fix_unit(call_desc_t *cd)
963 {
964
965         /* simple idletime calculation */
966
967         if((cd->shorthold_data.idle_time > 0) && (cd->shorthold_data.unitlen_time == 0))
968         {
969                 if((i4b_get_idletime(cd) + cd->shorthold_data.idle_time) <= SECOND)
970                 {
971                         NDBGL4(L4_TIMO, "%ld: outgoing-call-st, idle timeout, disconnecting!", (long)SECOND);
972                         (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
973                         i4b_l4_idle_timeout_ind(cd);
974                 }
975                 else
976                 {
977                         NDBGL4(L4_TIMO, "%ld: outgoing-call-st, activity, last_active=%ld, max_idle=%ld",
978                                         (long)SECOND, (long)i4b_get_idletime(cd), (long)cd->shorthold_data.idle_time);
979                         callout_reset(&cd->idle_timeout, hz / 2,
980                                         (void *)i4b_idle_check, cd);
981                         cd->timeout_active = 1;
982                 }
983         }
984
985         /* full shorthold mode calculation */
986
987         else if((cd->shorthold_data.unitlen_time > 0)
988                  && (cd->shorthold_data.unitlen_time > (cd->shorthold_data.idle_time + cd->shorthold_data.earlyhup_time)))
989         {
990                 switch(cd->idletime_state)
991                 {
992
993                 case IST_NONCHK:        /* end of non-check time */
994
995                         callout_reset(&cd->idle_timeout,
996                                         hz*(cd->shorthold_data.idle_time),
997                                         (void *)i4b_idle_check, cd);
998                         cd->idletimechk_start = SECOND;
999                         cd->idletime_state = IST_CHECK;
1000                         cd->timeout_active = 1;
1001                         NDBGL4(L4_TIMO, "%ld: outgoing-call, idletime check window reached!", (long)SECOND);
1002                         break;
1003
1004                 case IST_CHECK:         /* end of idletime chk */
1005                         if((i4b_get_idletime(cd) > cd->idletimechk_start) &&
1006                            (i4b_get_idletime(cd) <= SECOND))
1007                         {       /* activity detected */
1008                                 callout_reset(&cd->idle_timeout,
1009                                         hz*(cd->shorthold_data.earlyhup_time),
1010                                         (void *)i4b_idle_check, cd);
1011                                 cd->timeout_active = 1;
1012                                 cd->idletime_state = IST_SAFE;
1013                                 NDBGL4(L4_TIMO, "%ld: outgoing-call, activity at %ld, wait earlyhup-end", (long)SECOND, (long)i4b_get_idletime(cd));
1014                         }
1015                         else
1016                         {       /* no activity, hangup */
1017                                 NDBGL4(L4_TIMO, "%ld: outgoing-call, idle timeout, last activity at %ld", (long)SECOND, (long)i4b_get_idletime(cd));
1018                                 (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
1019                                 i4b_l4_idle_timeout_ind(cd);
1020                                 cd->idletime_state = IST_IDLE;
1021                         }
1022                         break;
1023
1024                 case IST_SAFE:  /* end of earlyhup time */
1025
1026                         callout_reset(&cd->idle_timeout,
1027                                 hz*(cd->shorthold_data.unitlen_time - 
1028                                   (cd->shorthold_data.idle_time +
1029                                   cd->shorthold_data.earlyhup_time)),
1030                                 (void *)i4b_idle_check, cd); 
1031                         cd->timeout_active = 1;
1032                         cd->idletime_state = IST_NONCHK;
1033
1034                         if(cd->aocd_flag == 0)
1035                         {
1036                                 cd->units_type = CHARGE_CALC;
1037                                 cd->cunits++;
1038                                 i4b_l4_charging_ind(cd);
1039                         }
1040                         
1041                         NDBGL4(L4_TIMO, "%ld: outgoing-call, earlyhup end, wait for idletime start", (long)SECOND);
1042                         break;
1043
1044                 default:
1045                         NDBGL4(L4_ERR, "outgoing-call: invalid idletime_state value!");
1046                         cd->idletime_state = IST_IDLE;
1047                         break;
1048                 }
1049         }
1050 }
1051
1052 /*---------------------------------------------------------------------------*
1053  *      variable unit algorithm B channel idle check timeout function
1054  *---------------------------------------------------------------------------*/
1055 static void
1056 i4b_idle_check_var_unit(call_desc_t *cd)
1057 {
1058         switch(cd->idletime_state)
1059         {
1060
1061         /* see if there has been any activity within the last idle_time seconds */
1062         case IST_CHECK:
1063                 if( i4b_get_idletime(cd) > (SECOND - cd->shorthold_data.idle_time))
1064                 {       /* activity detected */
1065                         /* check again in one second */
1066                         callout_reset(&cd->idle_timeout, hz,
1067                                         (void *)i4b_idle_check, cd);
1068                         cd->timeout_active = 1;
1069                         cd->idletime_state = IST_CHECK;
1070                         NDBGL4(L4_TIMO, "%ld: outgoing-call, var idle timeout - activity at %ld, continuing", (long)SECOND, (long)i4b_get_idletime(cd));
1071                 }
1072                 else
1073                 {       /* no activity, hangup */
1074                         NDBGL4(L4_TIMO, "%ld: outgoing-call, var idle timeout - last activity at %ld", (long)SECOND, (long)i4b_get_idletime(cd));
1075                         (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
1076                         i4b_l4_idle_timeout_ind(cd);
1077                         cd->idletime_state = IST_IDLE;
1078                 }
1079                 break;
1080
1081         default:
1082                 NDBGL4(L4_ERR, "outgoing-call: var idle timeout invalid idletime_state value!");
1083                 cd->idletime_state = IST_IDLE;
1084                 break;
1085         }
1086 }
1087
1088 #endif /* NI4B > 0 */