Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / sys / net / i4b / driver / i4b_isppp.c
1 /*
2  *   Copyright (c) 1997 Joerg Wunsch. All rights reserved.
3  *
4  *   Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *   1. Redistributions of source code must retain the above copyright
11  *      notice, this list of conditions and the following disclaimer.
12  *   2. Redistributions in binary form must reproduce the above copyright
13  *      notice, this list of conditions and the following disclaimer in the
14  *      documentation and/or other materials provided with the distribution.
15  *
16  *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  *   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  *   SUCH DAMAGE.
27  *
28  *---------------------------------------------------------------------------
29  *
30  *      i4b_isppp.c - isdn4bsd kernel SyncPPP driver
31  *      --------------------------------------------
32  *
33  *      Uses Serge Vakulenko's sppp backend (originally contributed with
34  *      the "cx" driver for Cronyx's HDLC-in-hardware device).  This driver
35  *      is only the glue between sppp and i4b.
36  *
37  *      $Id: i4b_isppp.c,v 1.44 2000/08/31 07:07:26 hm Exp $
38  *
39  * $FreeBSD: src/sys/i4b/driver/i4b_isppp.c,v 1.7.2.3 2003/02/06 14:50:53 gj Exp $
40  *
41  *      last edit-date: [Thu Aug 31 09:02:27 2000]
42  *
43  *---------------------------------------------------------------------------*/
44
45
46 #include "use_i4bisppp.h"
47
48 #if NI4BISPPP == 0
49 # error "You need to define `device sppp <N>' with options ISPPP"
50 #endif
51
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/mbuf.h>
55 #include <sys/socket.h>
56 #include <sys/errno.h>
57 #include <sys/sockio.h>
58 #include <sys/kernel.h>
59 #include <sys/thread2.h>
60
61 #include <net/if.h>
62 #include <net/if_arp.h>
63 #include <net/if_types.h>
64 #include <net/sppp/if_sppp.h>
65
66 #include <sys/time.h>
67 #include <net/bpf.h>
68
69 #include <net/i4b/include/machine/i4b_debug.h>
70 #include <net/i4b/include/machine/i4b_ioctl.h>
71
72 #include "../include/i4b_global.h"
73 #include "../include/i4b_l3l4.h"
74 #include "../layer4/i4b_l4.h"
75
76 #define PDEVSTATIC      static
77
78 #define ISPPP_FMT       "%s: "
79 #define ISPPP_ARG(sc)   ((sc)->sc_if.if_xname)
80 #define IFP2UNIT(ifp)   ((struct i4bisppp_softc *)ifp->if_softc)->sc_unit
81
82 #  define IOCTL_CMD_T u_long
83
84 PDEVSTATIC void i4bispppattach(void *);
85 PSEUDO_SET(i4bispppattach, i4b_isppp);
86
87 #define I4BISPPPACCT            1       /* enable accounting messages */
88 #define I4BISPPPACCTINTVL       2       /* accounting msg interval in secs */
89 #define I4BISPPPDISCDEBUG       1
90
91 #define PPP_HDRLEN              4       /* 4 octetts PPP header length  */
92
93 struct i4bisppp_softc {
94         /*
95          * struct sppp starts with a struct ifnet, but we gotta allocate
96          * more space for it.  NB: do not relocate this union, it must
97          * be first in isppp_softc.  The tls and tlf hooks below want to
98          * convert a ``struct sppp *'' into a ``struct isppp_softc *''.
99          */
100         union {
101                 struct ifnet scu_if;
102                 struct sppp scu_sp;
103         } sc_if_un;
104 #define sc_if sc_if_un.scu_if
105
106         int     sc_state;       /* state of the interface       */
107         int     sc_unit;        /* unit number                  */
108
109         call_desc_t *sc_cdp;    /* ptr to call descriptor       */
110
111 #ifdef I4BISPPPACCT
112         int sc_iinb;            /* isdn driver # of inbytes     */
113         int sc_ioutb;           /* isdn driver # of outbytes    */
114         int sc_inb;             /* # of bytes rx'd              */
115         int sc_outb;            /* # of bytes tx'd              */
116         int sc_linb;            /* last # of bytes rx'd         */
117         int sc_loutb;           /* last # of bytes tx'd         */
118         int sc_fn;              /* flag, first null acct        */
119 #endif
120
121         struct callout  sc_timeout;
122
123 } i4bisppp_softc[NI4BISPPP];
124
125 static void     i4bisppp_init_linktab(int unit);
126 static int      i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data,
127                                struct ucred *cr);
128
129 #if 0
130 static void     i4bisppp_send(struct ifnet *ifp);
131 #endif
132
133 static void     i4bisppp_start(struct ifnet *ifp);
134
135 #if 0 /* never used ??? */
136 static void     i4bisppp_timeout(void *cookie);
137 #endif
138
139 static void     i4bisppp_tls(struct sppp *sp);
140 static void     i4bisppp_tlf(struct sppp *sp);
141 static void     i4bisppp_state_changed(struct sppp *sp, int new_state);
142 static void     i4bisppp_negotiation_complete(struct sppp *sp);
143 static void     i4bisppp_watchdog(struct ifnet *ifp);
144 time_t          i4bisppp_idletime(int unit);
145
146 /* initialized by L4 */
147
148 static drvr_link_t i4bisppp_drvr_linktab[NI4BISPPP];
149 static isdn_link_t *isdn_linktab[NI4BISPPP];
150
151 enum i4bisppp_states {
152         ST_IDLE,                        /* initialized, ready, idle     */
153         ST_DIALING,                     /* dialling out to remote       */
154         ST_CONNECTED,                   /* connected to remote          */
155 };
156
157 /*===========================================================================*
158  *                      DEVICE DRIVER ROUTINES
159  *===========================================================================*/
160
161 /*---------------------------------------------------------------------------*
162  *      interface attach routine at kernel boot time
163  *---------------------------------------------------------------------------*/
164 PDEVSTATIC void
165 i4bispppattach(void *dummy)
166 {
167         struct i4bisppp_softc *sc = i4bisppp_softc;
168         int i;
169
170 #ifndef HACK_NO_PSEUDO_ATTACH_MSG
171 #ifdef SPPP_VJ
172         kprintf("i4bisppp: %d ISDN SyncPPP device(s) attached (VJ header compression)\n", NI4BISPPP);
173 #else
174         kprintf("i4bisppp: %d ISDN SyncPPP device(s) attached\n", NI4BISPPP);
175 #endif
176 #endif
177
178         for(i = 0; i < NI4BISPPP; sc++, i++) {
179                 i4bisppp_init_linktab(i);
180
181                 sc->sc_if.if_softc = sc;
182
183                 if_initname(&(sc->sc_if), "isp", i);
184                 sc->sc_if.if_mtu = PP_MTU;
185
186                 sc->sc_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT;
187
188                 sc->sc_if.if_type = IFT_ISDNBASIC;
189                 sc->sc_state = ST_IDLE;
190
191                 sc->sc_if.if_ioctl = i4bisppp_ioctl;
192
193                 /* actually initialized by sppp_attach() */
194                 /* sc->sc_if.if_output = sppp_output; */
195
196                 sc->sc_if.if_start = i4bisppp_start;
197
198                 sc->sc_if.if_hdrlen = 0;
199                 sc->sc_if.if_addrlen = 0;
200                 sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
201
202                 sc->sc_if.if_ipackets = 0;
203                 sc->sc_if.if_ierrors = 0;
204                 sc->sc_if.if_opackets = 0;
205                 sc->sc_if.if_oerrors = 0;
206                 sc->sc_if.if_collisions = 0;
207                 sc->sc_if.if_ibytes = 0;
208                 sc->sc_if.if_obytes = 0;
209                 sc->sc_if.if_imcasts = 0;
210                 sc->sc_if.if_omcasts = 0;
211                 sc->sc_if.if_iqdrops = 0;
212                 sc->sc_if.if_noproto = 0;
213
214 #if I4BISPPPACCT
215                 sc->sc_if.if_timer = 0;
216                 sc->sc_if.if_watchdog = i4bisppp_watchdog;
217                 sc->sc_iinb = 0;
218                 sc->sc_ioutb = 0;
219                 sc->sc_inb = 0;
220                 sc->sc_outb = 0;
221                 sc->sc_linb = 0;
222                 sc->sc_loutb = 0;
223                 sc->sc_fn = 1;
224 #endif
225
226                 sc->sc_if_un.scu_sp.pp_tls = i4bisppp_tls;
227                 sc->sc_if_un.scu_sp.pp_tlf = i4bisppp_tlf;
228                 sc->sc_if_un.scu_sp.pp_con = i4bisppp_negotiation_complete;
229                 sc->sc_if_un.scu_sp.pp_chg = i4bisppp_state_changed;
230
231                 sppp_attach(&sc->sc_if);
232 /* XXX: validate / add proper code */
233                 ether_ifattach_bpf(&sc->sc_if, ((struct arpcom*)sc)->ac_enaddr,
234                                    DLT_PPP, PPP_HDRLEN, NULL);
235                 callout_init(&sc->sc_timeout);
236         }
237 }
238
239 /*---------------------------------------------------------------------------*
240  *      process ioctl
241  *---------------------------------------------------------------------------*/
242 static int
243 i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data,
244                struct ucred *cr)
245 {
246         struct i4bisppp_softc *sc = ifp->if_softc;
247 #if 0
248         struct sppp *sp = (struct sppp *)sc;
249         struct ifaddr *ifa = (struct ifaddr *) data;
250         struct ifreq *ifr = (struct ifreq *) data;
251 #endif
252
253         int error;
254
255         error = sppp_ioctl(&sc->sc_if, cmd, data);
256         if (error)
257                 return error;
258
259         switch(cmd) {
260         case SIOCSIFFLAGS:
261 #if 0 /* never used ??? */
262                 crit_enter();
263                 if ((ifp->if_flags & IFF_UP) == 0)
264                         callout_stop(&sc->sc_timeout);
265                 crit_exit();
266 #endif
267                 break;
268         }
269
270         return 0;
271 }
272
273 /*---------------------------------------------------------------------------*
274  *      start output to ISDN B-channel
275  *---------------------------------------------------------------------------*/
276 static void
277 i4bisppp_start(struct ifnet *ifp)
278 {
279         struct i4bisppp_softc *sc = ifp->if_softc;
280         struct mbuf *m;
281         /* int s; */
282         int unit = IFP2UNIT(ifp);
283
284         if (sppp_isempty(ifp))
285                 return;
286
287         if(sc->sc_state != ST_CONNECTED)
288                 return;
289
290         /*
291          * crit_enter();
292          * ifp->if_flags |= IFF_OACTIVE; // - need to clear this somewhere
293          * crit_exit();
294          */
295
296         while ((m = sppp_dequeue(&sc->sc_if)) != NULL)
297         {
298                 BPF_MTAP(ifp, m);
299
300                 microtime(&ifp->if_lastchange);
301
302                 if(IF_QFULL(isdn_linktab[unit]->tx_queue))
303                 {
304                         NDBGL4(L4_ISPDBG, "isp%d, tx queue full!", unit);
305                         m_freem(m);
306                 }
307                 else
308                 {
309 #if 0
310                         sc->sc_if.if_obytes += m->m_pkthdr.len;
311 #endif
312                         sc->sc_outb += m->m_pkthdr.len;
313                         sc->sc_if.if_opackets++;
314
315                         IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
316                 }
317         }
318         isdn_linktab[unit]->bch_tx_start(isdn_linktab[unit]->unit,
319                                          isdn_linktab[unit]->channel);
320 }
321
322 #ifdef I4BISPPPACCT
323 /*---------------------------------------------------------------------------*
324  *      watchdog routine
325  *---------------------------------------------------------------------------*/
326 static void
327 i4bisppp_watchdog(struct ifnet *ifp)
328 {
329         struct i4bisppp_softc *sc = ifp->if_softc;
330         int unit = IFP2UNIT(ifp);
331         bchan_statistics_t bs;
332
333         (*isdn_linktab[unit]->bch_stat)
334                 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
335
336         sc->sc_ioutb += bs.outbytes;
337         sc->sc_iinb += bs.inbytes;
338
339         if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
340         {
341                 int ri = (sc->sc_iinb - sc->sc_linb)/I4BISPPPACCTINTVL;
342                 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BISPPPACCTINTVL;
343
344                 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
345                         sc->sc_fn = 0;
346                 else
347                         sc->sc_fn = 1;
348
349                 sc->sc_linb = sc->sc_iinb;
350                 sc->sc_loutb = sc->sc_ioutb;
351
352                 i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_DURING,
353                          sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb);
354         }
355         sc->sc_if.if_timer = I4BISPPPACCTINTVL;
356
357 #if 0 /* old stuff, keep it around */
358         kprintf(ISPPP_FMT "transmit timeout\n", ISPPP_ARG(sc));
359         i4bisppp_start(ifp);
360 #endif
361 }
362 #endif /* I4BISPPPACCT */
363
364 /*
365  *===========================================================================*
366  *                      SyncPPP layer interface routines
367  *===========================================================================*
368  */
369
370 #if 0 /* never used ??? */
371 /*---------------------------------------------------------------------------*
372  *      just an alias for i4bisppp_tls, but of type timeout_t
373  *---------------------------------------------------------------------------*/
374 static void
375 i4bisppp_timeout(void *cookie)
376 {
377         i4bisppp_tls((struct sppp *)cookie);
378 }
379 #endif
380
381 /*---------------------------------------------------------------------------*
382  *      PPP this-layer-started action
383  *---------------------------------------------------------------------------*
384  */
385 static void
386 i4bisppp_tls(struct sppp *sp)
387 {
388         struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
389         struct ifnet *ifp = (struct ifnet *)sp;
390
391         if(sc->sc_state == ST_CONNECTED)
392                 return;
393
394         i4b_l4_dialout(BDRV_ISPPP, IFP2UNIT(ifp));
395 }
396
397 /*---------------------------------------------------------------------------*
398  *      PPP this-layer-finished action
399  *---------------------------------------------------------------------------*
400  */
401 static void
402 i4bisppp_tlf(struct sppp *sp)
403 {
404         struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
405 /*      call_desc_t *cd = sc->sc_cdp;   */
406         struct ifnet *ifp = (struct ifnet *)sp;
407
408         if(sc->sc_state != ST_CONNECTED)
409                 return;
410
411 #if 0 /* never used ??? */
412         callout_stop(&sc->sc_timeout);
413 #endif
414
415         i4b_l4_drvrdisc(BDRV_ISPPP, IFP2UNIT(ifp));
416 }
417 /*---------------------------------------------------------------------------*
418  *      PPP interface phase change
419  *---------------------------------------------------------------------------*
420  */
421 static void
422 i4bisppp_state_changed(struct sppp *sp, int new_state)
423 {
424         struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
425
426         i4b_l4_ifstate_changed(sc->sc_cdp, new_state);
427 }
428
429 /*---------------------------------------------------------------------------*
430  *      PPP control protocol negotiation complete (run ip-up script now)
431  *---------------------------------------------------------------------------*
432  */
433 static void
434 i4bisppp_negotiation_complete(struct sppp *sp)
435 {
436         struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
437
438         i4b_l4_negcomplete(sc->sc_cdp);
439 }
440
441 /*===========================================================================*
442  *                      ISDN INTERFACE ROUTINES
443  *===========================================================================*/
444
445 /*---------------------------------------------------------------------------*
446  *      this routine is called from L4 handler at connect time
447  *---------------------------------------------------------------------------*/
448 static void
449 i4bisppp_connect(int unit, void *cdp)
450 {
451         struct i4bisppp_softc *sc = &i4bisppp_softc[unit];
452         struct sppp *sp = &sc->sc_if_un.scu_sp;
453
454         crit_enter();
455
456         sc->sc_cdp = (call_desc_t *)cdp;
457         sc->sc_state = ST_CONNECTED;
458
459 #if I4BISPPPACCT
460         sc->sc_iinb = 0;
461         sc->sc_ioutb = 0;
462         sc->sc_inb = 0;
463         sc->sc_outb = 0;
464         sc->sc_linb = 0;
465         sc->sc_loutb = 0;
466         sc->sc_if.if_timer = I4BISPPPACCTINTVL;
467 #endif
468
469 #if 0 /* never used ??? */
470         callout_stop(&sc->sc_timeout);
471 #endif
472
473         sp->pp_up(sp);          /* tell PPP we are ready */
474         sp->pp_last_sent = sp->pp_last_recv = SECOND;
475
476         crit_exit();
477 }
478
479 /*---------------------------------------------------------------------------*
480  *      this routine is called from L4 handler at disconnect time
481  *---------------------------------------------------------------------------*/
482 static void
483 i4bisppp_disconnect(int unit, void *cdp)
484 {
485         call_desc_t *cd = (call_desc_t *)cdp;
486         struct i4bisppp_softc *sc = &i4bisppp_softc[unit];
487         struct sppp *sp = &sc->sc_if_un.scu_sp;
488
489         crit_enter();
490
491         /* new stuff to check that the active channel is being closed */
492         if (cd != sc->sc_cdp)
493         {
494                 NDBGL4(L4_ISPDBG, "isp%d, channel%d not active!", unit, cd->channelid);
495                 crit_exit();
496                 return;
497         }
498
499 #if I4BISPPPACCT
500         sc->sc_if.if_timer = 0;
501 #endif
502
503         i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_FINAL,
504                  sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb);
505
506         if (sc->sc_state == ST_CONNECTED)
507         {
508 #if 0 /* never used ??? */
509                 callout_stop(&sc->sc_timeout);
510 #endif
511                 sc->sc_cdp = NULL;
512                 /* do this here because pp_down calls i4bisppp_tlf */
513                 sc->sc_state = ST_IDLE;
514                 sp->pp_down(sp);        /* tell PPP we have hung up */
515         }
516
517         crit_exit();
518 }
519
520 /*---------------------------------------------------------------------------*
521  *      this routine is used to give a feedback from userland demon
522  *      in case of dial problems
523  *---------------------------------------------------------------------------*/
524 static void
525 i4bisppp_dialresponse(int unit, int status, cause_t cause)
526 {
527         struct i4bisppp_softc *sc = &i4bisppp_softc[unit];
528         struct sppp *sp = &sc->sc_if_un.scu_sp;
529
530         NDBGL4(L4_ISPDBG, "isp%d: status=%d, cause=%d", unit, status, cause);
531
532         if(status != DSTAT_NONE)
533         {
534                 struct mbuf *m;
535
536                 NDBGL4(L4_ISPDBG, "isp%d: clearing queues", unit);
537
538                 if(!(sppp_isempty(&sc->sc_if)))
539                 {
540                         while((m = sppp_dequeue(&sc->sc_if)) != NULL)
541                                 m_freem(m);
542                 }
543
544                 sc->sc_cdp = NULL;
545                 /* do this here because pp_down calls i4bisppp_tlf */
546                 sc->sc_state = ST_IDLE;
547                 /*
548                  * Ahh, sppp doesn't like to get a down event when
549                  * dialing fails. So first tell it that we are up
550                  * (doesn't hurt us since sc_state != ST_CONNECTED)
551                  * and then go down.
552                  */
553                 sp->pp_up(sp);
554                 sp->pp_down(sp);
555         }
556 }
557
558 /*---------------------------------------------------------------------------*
559  *      interface up/down
560  *---------------------------------------------------------------------------*/
561 static void
562 i4bisppp_updown(int unit, int updown)
563 {
564         /* could probably do something useful here */
565 }
566
567 /*---------------------------------------------------------------------------*
568  *      this routine is called from the HSCX interrupt handler
569  *      when a new frame (mbuf) has been received and was put on
570  *      the rx queue.
571  *---------------------------------------------------------------------------*/
572 static void
573 i4bisppp_rx_data_rdy(int unit)
574 {
575         struct i4bisppp_softc *sc = &i4bisppp_softc[unit];
576         struct mbuf *m;
577
578         if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
579                 return;
580
581         m->m_pkthdr.rcvif = &sc->sc_if;
582         m->m_pkthdr.len = m->m_len;
583
584         microtime(&sc->sc_if.if_lastchange);
585
586         sc->sc_if.if_ipackets++;
587 #if 0
588         sc->sc_if.if_ibytes += m->m_pkthdr.len;
589 #endif
590
591 #if I4BISPPPACCT
592         sc->sc_inb += m->m_pkthdr.len;
593 #endif
594
595 #ifdef I4BISPPPDEBUG
596         kprintf("i4bisppp_rx_data_ready: received packet!\n");
597 #endif
598
599         BPF_MTAP(&sc->sc_if, m);
600
601         crit_enter();
602         sppp_input(&sc->sc_if, m);
603         crit_exit();
604 }
605
606 /*---------------------------------------------------------------------------*
607  *      this routine is called from the HSCX interrupt handler
608  *      when the last frame has been sent out and there is no
609  *      further frame (mbuf) in the tx queue.
610  *---------------------------------------------------------------------------*/
611 static void
612 i4bisppp_tx_queue_empty(int unit)
613 {
614         i4bisppp_start(&i4bisppp_softc[unit].sc_if);
615 }
616
617 /*---------------------------------------------------------------------------*
618  *      THIS should be used instead of last_active_time to implement
619  *      an activity timeout mechanism.
620  *
621  *      Sending back the time difference unneccessarily complicates the
622  *      idletime checks in i4b_l4.c. Return the largest time instead.
623  *      That way the code in i4b_l4.c needs only minimal changes.
624  *---------------------------------------------------------------------------*/
625 time_t
626 i4bisppp_idletime(int unit)
627 {
628         struct sppp *sp;
629         sp = (struct sppp *) &i4bisppp_softc[unit];
630
631         return((sp->pp_last_recv < sp->pp_last_sent) ?
632                         sp->pp_last_sent : sp->pp_last_recv);
633 }
634
635 /*---------------------------------------------------------------------------*
636  *      this routine is called from the HSCX interrupt handler
637  *      each time a packet is received or transmitted. It should
638  *      be used to implement an activity timeout mechanism.
639  *---------------------------------------------------------------------------*/
640 static void
641 i4bisppp_activity(int unit, int rxtx)
642 {
643         i4bisppp_softc[unit].sc_cdp->last_active_time = SECOND;
644 }
645
646 /*---------------------------------------------------------------------------*
647  *      return this drivers linktab address
648  *---------------------------------------------------------------------------*/
649 drvr_link_t *
650 i4bisppp_ret_linktab(int unit)
651 {
652         return(&i4bisppp_drvr_linktab[unit]);
653 }
654
655 /*---------------------------------------------------------------------------*
656  *      setup the isdn_linktab for this driver
657  *---------------------------------------------------------------------------*/
658 void
659 i4bisppp_set_linktab(int unit, isdn_link_t *ilt)
660 {
661         isdn_linktab[unit] = ilt;
662 }
663
664 /*---------------------------------------------------------------------------*
665  *      initialize this drivers linktab
666  *---------------------------------------------------------------------------*/
667 static void
668 i4bisppp_init_linktab(int unit)
669 {
670         i4bisppp_drvr_linktab[unit].unit = unit;
671         i4bisppp_drvr_linktab[unit].bch_rx_data_ready = i4bisppp_rx_data_rdy;
672         i4bisppp_drvr_linktab[unit].bch_tx_queue_empty = i4bisppp_tx_queue_empty;
673         i4bisppp_drvr_linktab[unit].bch_activity = i4bisppp_activity;
674         i4bisppp_drvr_linktab[unit].line_connected = i4bisppp_connect;
675         i4bisppp_drvr_linktab[unit].line_disconnected = i4bisppp_disconnect;
676         i4bisppp_drvr_linktab[unit].dial_response = i4bisppp_dialresponse;
677         i4bisppp_drvr_linktab[unit].updown_ind = i4bisppp_updown;
678 }
679
680 /*===========================================================================*/