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