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