kernel tree reorganization stage 1: Major cvs repository work (not logged as
[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  * $DragonFly: src/sys/net/i4b/driver/i4b_isppp.c,v 1.3 2003/08/07 21:17:25 dillon Exp $
41  *
42  *      last edit-date: [Thu Aug 31 09:02:27 2000]
43  *
44  *---------------------------------------------------------------------------*/
45
46
47 #ifndef __NetBSD__
48 #endif
49 #include "use_i4bisppp.h"
50
51 #ifndef __NetBSD__
52 #if NI4BISPPP == 0
53 # error "You need to define `device sppp <N>' with options ISPPP"
54 #endif
55 #endif
56
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/mbuf.h>
60 #include <sys/socket.h>
61 #include <sys/errno.h>
62 #include <sys/ioccom.h>
63 #include <sys/sockio.h>
64 #include <sys/kernel.h>
65
66 #include <net/if.h>
67 #include <net/if_types.h>
68 #include <net/if_sppp.h>
69
70
71 #if defined(__FreeBSD_version) &&  __FreeBSD_version >= 400008                
72 #include "use_bpf.h"     
73 #else
74 #include "bpfilter.h"
75 #endif
76 #if NBPFILTER > 0 || NBPF > 0
77 #include <sys/time.h>
78 #include <net/bpf.h>
79 #endif
80
81 #ifdef __FreeBSD__
82 #include <net/i4b/include/machine/i4b_debug.h>
83 #include <net/i4b/include/machine/i4b_ioctl.h>
84 #else
85 #include <i4b/i4b_ioctl.h>
86 #include <i4b/i4b_cause.h>
87 #include <i4b/i4b_debug.h>
88 #endif
89
90 #include "../include/i4b_global.h"
91 #include "../include/i4b_l3l4.h"
92 #include "../layer4/i4b_l4.h"
93
94 #ifdef __FreeBSD__
95 #define ISPPP_FMT       "isp%d: "
96 #define ISPPP_ARG(sc)   ((sc)->sc_if.if_unit)
97 #define PDEVSTATIC      static
98 #define IFP2UNIT(ifp)   (ifp)->if_unit
99                 
100 # if __FreeBSD_version >= 300001
101 #  define CALLOUT_INIT(chan)            callout_handle_init(chan)
102 #  define TIMEOUT(fun, arg, chan, tick) chan = timeout(fun, arg, tick)
103 #  define UNTIMEOUT(fun, arg, chan)     untimeout(fun, arg, chan)
104 #  define IOCTL_CMD_T u_long
105 # else
106 #  define CALLOUT_INIT(chan)            do {} while(0)
107 #  define TIMEOUT(fun, arg, chan, tick) timeout(fun, arg, tick)
108 #  define UNTIMEOUT(fun, arg, chan)     untimeout(fun, arg)
109 #  define IOCTL_CMD_T int
110 # endif
111
112 #elif defined __NetBSD__ || defined __OpenBSD__
113 #define ISPPP_FMT       "%s: "
114 #define ISPPP_ARG(sc)   ((sc)->sc_if.if_xname)
115 #define PDEVSTATIC      /* not static */
116 #define IOCTL_CMD_T     u_long
117 #define IFP2UNIT(ifp)   ((struct i4bisppp_softc *)ifp->if_softc)->sc_unit
118 #else
119 # error "What system are you using?"
120 #endif
121
122 #ifdef __FreeBSD__
123 PDEVSTATIC void i4bispppattach(void *);
124 PSEUDO_SET(i4bispppattach, i4b_isppp);
125 #else
126 PDEVSTATIC void i4bispppattach(void);
127 #endif
128
129 #define I4BISPPPACCT            1       /* enable accounting messages */
130 #define I4BISPPPACCTINTVL       2       /* accounting msg interval in secs */
131 #define I4BISPPPDISCDEBUG       1       
132
133 #define PPP_HDRLEN              4       /* 4 octetts PPP header length  */
134
135 struct i4bisppp_softc {
136         /*
137          * struct sppp starts with a struct ifnet, but we gotta allocate
138          * more space for it.  NB: do not relocate this union, it must
139          * be first in isppp_softc.  The tls and tlf hooks below want to
140          * convert a ``struct sppp *'' into a ``struct isppp_softc *''.
141          */
142         union {
143                 struct ifnet scu_if;
144                 struct sppp scu_sp;
145         } sc_if_un;
146 #define sc_if sc_if_un.scu_if
147
148         int     sc_state;       /* state of the interface       */
149
150 #ifndef __FreeBSD__
151         int     sc_unit;        /* unit number for Net/OpenBSD  */
152 #endif
153
154         call_desc_t *sc_cdp;    /* ptr to call descriptor       */
155
156 #ifdef I4BISPPPACCT
157         int sc_iinb;            /* isdn driver # of inbytes     */
158         int sc_ioutb;           /* isdn driver # of outbytes    */
159         int sc_inb;             /* # of bytes rx'd              */
160         int sc_outb;            /* # of bytes tx'd              */
161         int sc_linb;            /* last # of bytes rx'd         */
162         int sc_loutb;           /* last # of bytes tx'd         */
163         int sc_fn;              /* flag, first null acct        */
164 #endif
165
166 #if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
167         struct callout_handle sc_ch;
168 #endif
169
170 } i4bisppp_softc[NI4BISPPP];
171
172 static void     i4bisppp_init_linktab(int unit);
173 static int      i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data);
174
175 #if 0
176 static void     i4bisppp_send(struct ifnet *ifp);
177 #endif
178
179 static void     i4bisppp_start(struct ifnet *ifp);
180
181 #if 0 /* never used ??? */
182 static void     i4bisppp_timeout(void *cookie);
183 #endif
184
185 static void     i4bisppp_tls(struct sppp *sp);
186 static void     i4bisppp_tlf(struct sppp *sp);
187 static void     i4bisppp_state_changed(struct sppp *sp, int new_state);
188 static void     i4bisppp_negotiation_complete(struct sppp *sp);
189 static void     i4bisppp_watchdog(struct ifnet *ifp);
190 time_t          i4bisppp_idletime(int unit);
191
192 /* initialized by L4 */
193
194 static drvr_link_t i4bisppp_drvr_linktab[NI4BISPPP];
195 static isdn_link_t *isdn_linktab[NI4BISPPP];
196
197 enum i4bisppp_states {
198         ST_IDLE,                        /* initialized, ready, idle     */
199         ST_DIALING,                     /* dialling out to remote       */
200         ST_CONNECTED,                   /* connected to remote          */
201 };
202
203 /*===========================================================================*
204  *                      DEVICE DRIVER ROUTINES
205  *===========================================================================*/
206
207 /*---------------------------------------------------------------------------*
208  *      interface attach routine at kernel boot time
209  *---------------------------------------------------------------------------*/
210 PDEVSTATIC void
211 #ifdef __FreeBSD__
212 i4bispppattach(void *dummy)
213 #else
214 i4bispppattach()
215 #endif
216 {
217         struct i4bisppp_softc *sc = i4bisppp_softc;
218         int i;
219
220 #ifndef HACK_NO_PSEUDO_ATTACH_MSG
221 #ifdef SPPP_VJ
222         printf("i4bisppp: %d ISDN SyncPPP device(s) attached (VJ header compression)\n", NI4BISPPP);
223 #else
224         printf("i4bisppp: %d ISDN SyncPPP device(s) attached\n", NI4BISPPP);
225 #endif
226 #endif
227
228         for(i = 0; i < NI4BISPPP; sc++, i++) {
229                 i4bisppp_init_linktab(i);
230                 
231                 sc->sc_if.if_softc = sc;
232
233 #ifdef __FreeBSD__              
234                 sc->sc_if.if_name = "isp";
235 #if defined(__FreeBSD_version) && __FreeBSD_version < 300001
236                 sc->sc_if.if_next = NULL;
237 #endif
238                 sc->sc_if.if_unit = i;
239 #else
240                 sprintf(sc->sc_if.if_xname, "isp%d", i);
241                 sc->sc_unit = i;
242 #endif
243
244                 sc->sc_if.if_mtu = PP_MTU;
245
246 #ifdef __NetBSD__
247                 sc->sc_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT |
248                                         IFF_MULTICAST;
249 #else
250                 sc->sc_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT;
251 #endif
252
253                 sc->sc_if.if_type = IFT_ISDNBASIC;
254                 sc->sc_state = ST_IDLE;
255
256                 sc->sc_if.if_ioctl = i4bisppp_ioctl;
257
258                 /* actually initialized by sppp_attach() */
259                 /* sc->sc_if.if_output = sppp_output; */
260
261                 sc->sc_if.if_start = i4bisppp_start;
262
263                 sc->sc_if.if_hdrlen = 0;
264                 sc->sc_if.if_addrlen = 0;
265                 sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
266
267                 sc->sc_if.if_ipackets = 0;
268                 sc->sc_if.if_ierrors = 0;
269                 sc->sc_if.if_opackets = 0;
270                 sc->sc_if.if_oerrors = 0;
271                 sc->sc_if.if_collisions = 0;
272                 sc->sc_if.if_ibytes = 0;
273                 sc->sc_if.if_obytes = 0;
274                 sc->sc_if.if_imcasts = 0;
275                 sc->sc_if.if_omcasts = 0;
276                 sc->sc_if.if_iqdrops = 0;
277                 sc->sc_if.if_noproto = 0;
278
279 #if I4BISPPPACCT
280                 sc->sc_if.if_timer = 0; 
281                 sc->sc_if.if_watchdog = i4bisppp_watchdog;      
282                 sc->sc_iinb = 0;
283                 sc->sc_ioutb = 0;
284                 sc->sc_inb = 0;
285                 sc->sc_outb = 0;
286                 sc->sc_linb = 0;
287                 sc->sc_loutb = 0;
288                 sc->sc_fn = 1;
289 #endif
290
291                 sc->sc_if_un.scu_sp.pp_tls = i4bisppp_tls;
292                 sc->sc_if_un.scu_sp.pp_tlf = i4bisppp_tlf;
293                 sc->sc_if_un.scu_sp.pp_con = i4bisppp_negotiation_complete;
294                 sc->sc_if_un.scu_sp.pp_chg = i4bisppp_state_changed;
295
296                 sppp_attach(&sc->sc_if);
297 #if defined(__FreeBSD_version) && ((__FreeBSD_version >= 500009) || (410000 <= __FreeBSD_version && __FreeBSD_version < 500000))
298                 /* do not call bpfattach in ether_ifattach */
299                 ether_ifattach(&sc->sc_if, 0);
300 #else
301                 if_attach(&sc->sc_if);
302 #endif
303
304 #if NBPFILTER > 0 || NBPF > 0
305 #ifdef __FreeBSD__
306                 bpfattach(&sc->sc_if, DLT_PPP, PPP_HDRLEN);
307                 CALLOUT_INIT(&sc->sc_ch);
308 #endif /* __FreeBSD__ */
309 #ifdef __NetBSD__
310                 bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_PPP, sizeof(u_int));
311 #endif
312 #endif          
313         }
314 }
315
316 /*---------------------------------------------------------------------------*
317  *      process ioctl
318  *---------------------------------------------------------------------------*/
319 static int
320 i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data)
321 {
322         struct i4bisppp_softc *sc = ifp->if_softc;
323 #if 0
324         struct sppp *sp = (struct sppp *)sc;
325         struct ifaddr *ifa = (struct ifaddr *) data;
326         struct ifreq *ifr = (struct ifreq *) data;
327 #endif
328
329         int error;
330
331         error = sppp_ioctl(&sc->sc_if, cmd, data);
332         if (error)
333                 return error;
334
335         switch(cmd) {
336         case SIOCSIFFLAGS:
337 #if 0 /* never used ??? */
338                 x = splimp();
339                 if ((ifp->if_flags & IFF_UP) == 0)
340                         UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch);
341                 splx(x);
342 #endif
343                 break;
344         }
345
346         return 0;
347 }
348
349 /*---------------------------------------------------------------------------*
350  *      start output to ISDN B-channel
351  *---------------------------------------------------------------------------*/
352 static void
353 i4bisppp_start(struct ifnet *ifp)
354 {
355         struct i4bisppp_softc *sc = ifp->if_softc;
356         struct mbuf *m;
357         /* int s; */
358         int unit = IFP2UNIT(ifp);
359
360         if (sppp_isempty(ifp))
361                 return;
362
363         if(sc->sc_state != ST_CONNECTED)
364                 return;
365
366         /*
367          * s = splimp();
368          * ifp->if_flags |= IFF_OACTIVE; // - need to clear this somewhere
369          * splx(s);
370          */
371
372         while ((m = sppp_dequeue(&sc->sc_if)) != NULL)
373         {
374
375 #if NBPFILTER > 0 || NBPF > 0
376 #ifdef __FreeBSD__
377                 if (ifp->if_bpf)
378                         bpf_mtap(ifp, m);
379 #endif /* __FreeBSD__ */
380
381 #ifdef __NetBSD__
382                 if (ifp->if_bpf)
383                         bpf_mtap(ifp->if_bpf, m);
384 #endif
385 #endif /* NBPFILTER > 0 || NBPF > 0 */
386
387                 microtime(&ifp->if_lastchange);
388
389                 IF_LOCK(isdn_linktab[unit]->tx_queue);
390                 if(_IF_QFULL(isdn_linktab[unit]->tx_queue))
391                 {
392                         NDBGL4(L4_ISPDBG, "isp%d, tx queue full!", unit);
393                         m_freem(m);
394                 }
395                 else
396                 {
397 #if 0
398                         sc->sc_if.if_obytes += m->m_pkthdr.len;
399 #endif
400                         sc->sc_outb += m->m_pkthdr.len;
401                         sc->sc_if.if_opackets++;
402
403                         _IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
404                 }
405                 IF_UNLOCK(isdn_linktab[unit]->tx_queue);
406         }
407         isdn_linktab[unit]->bch_tx_start(isdn_linktab[unit]->unit,
408                                          isdn_linktab[unit]->channel);
409 }
410
411 #ifdef I4BISPPPACCT
412 /*---------------------------------------------------------------------------*
413  *      watchdog routine
414  *---------------------------------------------------------------------------*/
415 static void
416 i4bisppp_watchdog(struct ifnet *ifp)
417 {
418         struct i4bisppp_softc *sc = ifp->if_softc;
419         int unit = IFP2UNIT(ifp);
420         bchan_statistics_t bs;
421         
422         (*isdn_linktab[unit]->bch_stat)
423                 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
424
425         sc->sc_ioutb += bs.outbytes;
426         sc->sc_iinb += bs.inbytes;
427         
428         if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
429         {
430                 int ri = (sc->sc_iinb - sc->sc_linb)/I4BISPPPACCTINTVL;
431                 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BISPPPACCTINTVL;
432
433                 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
434                         sc->sc_fn = 0;
435                 else
436                         sc->sc_fn = 1;
437                         
438                 sc->sc_linb = sc->sc_iinb;
439                 sc->sc_loutb = sc->sc_ioutb;
440
441                 i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_DURING,
442                          sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb);
443         }
444         sc->sc_if.if_timer = I4BISPPPACCTINTVL;         
445
446 #if 0 /* old stuff, keep it around */
447         printf(ISPPP_FMT "transmit timeout\n", ISPPP_ARG(sc));
448         i4bisppp_start(ifp);
449 #endif
450 }
451 #endif /* I4BISPPPACCT */
452
453 /*
454  *===========================================================================*
455  *                      SyncPPP layer interface routines
456  *===========================================================================*
457  */
458
459 #if 0 /* never used ??? */
460 /*---------------------------------------------------------------------------*
461  *      just an alias for i4bisppp_tls, but of type timeout_t
462  *---------------------------------------------------------------------------*/
463 static void
464 i4bisppp_timeout(void *cookie)
465 {
466         i4bisppp_tls((struct sppp *)cookie);
467 }
468 #endif
469
470 /*---------------------------------------------------------------------------*
471  *      PPP this-layer-started action
472  *---------------------------------------------------------------------------*
473  */
474 static void
475 i4bisppp_tls(struct sppp *sp)
476 {
477         struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
478         struct ifnet *ifp = (struct ifnet *)sp;
479
480         if(sc->sc_state == ST_CONNECTED)
481                 return;
482
483         i4b_l4_dialout(BDRV_ISPPP, IFP2UNIT(ifp));
484 }
485
486 /*---------------------------------------------------------------------------*
487  *      PPP this-layer-finished action
488  *---------------------------------------------------------------------------*
489  */
490 static void
491 i4bisppp_tlf(struct sppp *sp)
492 {
493         struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
494 /*      call_desc_t *cd = sc->sc_cdp;   */
495         struct ifnet *ifp = (struct ifnet *)sp; 
496         
497         if(sc->sc_state != ST_CONNECTED)
498                 return;
499
500 #if 0 /* never used ??? */
501         UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch);
502 #endif
503
504         i4b_l4_drvrdisc(BDRV_ISPPP, IFP2UNIT(ifp));
505 }
506 /*---------------------------------------------------------------------------*
507  *      PPP interface phase change
508  *---------------------------------------------------------------------------*
509  */
510 static void
511 i4bisppp_state_changed(struct sppp *sp, int new_state)
512 {
513         struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
514         
515         i4b_l4_ifstate_changed(sc->sc_cdp, new_state);
516 }
517
518 /*---------------------------------------------------------------------------*
519  *      PPP control protocol negotiation complete (run ip-up script now)
520  *---------------------------------------------------------------------------*
521  */
522 static void
523 i4bisppp_negotiation_complete(struct sppp *sp)
524 {
525         struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
526         
527         i4b_l4_negcomplete(sc->sc_cdp);
528 }
529
530 /*===========================================================================*
531  *                      ISDN INTERFACE ROUTINES
532  *===========================================================================*/
533
534 /*---------------------------------------------------------------------------*
535  *      this routine is called from L4 handler at connect time
536  *---------------------------------------------------------------------------*/
537 static void
538 i4bisppp_connect(int unit, void *cdp)
539 {
540         struct i4bisppp_softc *sc = &i4bisppp_softc[unit];
541         struct sppp *sp = &sc->sc_if_un.scu_sp;
542         int s = splimp();
543
544         sc->sc_cdp = (call_desc_t *)cdp;
545         sc->sc_state = ST_CONNECTED;
546
547 #if I4BISPPPACCT
548         sc->sc_iinb = 0;
549         sc->sc_ioutb = 0;
550         sc->sc_inb = 0;
551         sc->sc_outb = 0;
552         sc->sc_linb = 0;
553         sc->sc_loutb = 0;
554         sc->sc_if.if_timer = I4BISPPPACCTINTVL;
555 #endif
556         
557 #if 0 /* never used ??? */
558         UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch);
559 #endif
560
561         sp->pp_up(sp);          /* tell PPP we are ready */
562 #ifndef __NetBSD__
563         sp->pp_last_sent = sp->pp_last_recv = SECOND;
564 #endif
565         splx(s);
566 }
567
568 /*---------------------------------------------------------------------------*
569  *      this routine is called from L4 handler at disconnect time
570  *---------------------------------------------------------------------------*/
571 static void
572 i4bisppp_disconnect(int unit, void *cdp)
573 {
574         call_desc_t *cd = (call_desc_t *)cdp;
575         struct i4bisppp_softc *sc = &i4bisppp_softc[unit];
576         struct sppp *sp = &sc->sc_if_un.scu_sp;
577
578         int s = splimp();
579
580         /* new stuff to check that the active channel is being closed */
581         if (cd != sc->sc_cdp)
582         {
583                 NDBGL4(L4_ISPDBG, "isp%d, channel%d not active!", unit, cd->channelid);
584                 splx(s);
585                 return;
586         }
587
588 #if I4BISPPPACCT
589         sc->sc_if.if_timer = 0;
590 #endif
591
592         i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_FINAL,
593                  sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb);
594         
595         if (sc->sc_state == ST_CONNECTED)
596         {
597 #if 0 /* never used ??? */
598                 UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch);
599 #endif
600                 sc->sc_cdp = (call_desc_t *)0;  
601                 /* do this here because pp_down calls i4bisppp_tlf */
602                 sc->sc_state = ST_IDLE;
603                 sp->pp_down(sp);        /* tell PPP we have hung up */
604         }
605
606         splx(s);
607 }
608
609 /*---------------------------------------------------------------------------*
610  *      this routine is used to give a feedback from userland demon
611  *      in case of dial problems
612  *---------------------------------------------------------------------------*/
613 static void
614 i4bisppp_dialresponse(int unit, int status, cause_t cause)
615 {
616         struct i4bisppp_softc *sc = &i4bisppp_softc[unit];
617         struct sppp *sp = &sc->sc_if_un.scu_sp;
618
619         NDBGL4(L4_ISPDBG, "isp%d: status=%d, cause=%d", unit, status, cause);
620
621         if(status != DSTAT_NONE)
622         {
623                 struct mbuf *m;
624                 
625                 NDBGL4(L4_ISPDBG, "isp%d: clearing queues", unit);
626
627                 if(!(sppp_isempty(&sc->sc_if)))
628                 {
629                         while((m = sppp_dequeue(&sc->sc_if)) != NULL)
630                                 m_freem(m);
631                 }
632
633                 sc->sc_cdp = (call_desc_t *)0;
634                 /* do this here because pp_down calls i4bisppp_tlf */
635                 sc->sc_state = ST_IDLE;
636                 /*
637                  * Ahh, sppp doesn't like to get a down event when
638                  * dialing fails. So first tell it that we are up
639                  * (doesn't hurt us since sc_state != ST_CONNECTED)
640                  * and then go down.
641                  */
642                 sp->pp_up(sp);
643                 sp->pp_down(sp);
644         }
645 }
646         
647 /*---------------------------------------------------------------------------*
648  *      interface up/down
649  *---------------------------------------------------------------------------*/
650 static void
651 i4bisppp_updown(int unit, int updown)
652 {
653         /* could probably do something useful here */
654 }
655         
656 /*---------------------------------------------------------------------------*
657  *      this routine is called from the HSCX interrupt handler
658  *      when a new frame (mbuf) has been received and was put on
659  *      the rx queue.
660  *---------------------------------------------------------------------------*/
661 static void
662 i4bisppp_rx_data_rdy(int unit)
663 {
664         struct i4bisppp_softc *sc = &i4bisppp_softc[unit];
665         struct mbuf *m;
666         int s;
667         
668         if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
669                 return;
670
671         m->m_pkthdr.rcvif = &sc->sc_if;
672         m->m_pkthdr.len = m->m_len;
673
674         microtime(&sc->sc_if.if_lastchange);
675
676         sc->sc_if.if_ipackets++;
677 #if 0
678         sc->sc_if.if_ibytes += m->m_pkthdr.len;
679 #endif
680
681 #if I4BISPPPACCT
682         sc->sc_inb += m->m_pkthdr.len;
683 #endif
684         
685 #ifdef I4BISPPPDEBUG
686         printf("i4bisppp_rx_data_ready: received packet!\n");
687 #endif
688
689 #if NBPFILTER > 0 || NBPF > 0
690
691 #ifdef __FreeBSD__      
692         if(sc->sc_if.if_bpf)
693                 bpf_mtap(&sc->sc_if, m);
694 #endif /* __FreeBSD__ */
695
696 #ifdef __NetBSD__
697         if(sc->sc_if.if_bpf)
698                 bpf_mtap(sc->sc_if.if_bpf, m);
699 #endif
700
701 #endif /* NBPFILTER > 0  || NBPF > 0 */
702
703         s = splimp();
704
705         sppp_input(&sc->sc_if, m);
706
707         splx(s);
708 }
709
710 /*---------------------------------------------------------------------------*
711  *      this routine is called from the HSCX interrupt handler
712  *      when the last frame has been sent out and there is no
713  *      further frame (mbuf) in the tx queue.
714  *---------------------------------------------------------------------------*/
715 static void
716 i4bisppp_tx_queue_empty(int unit)
717 {
718         i4bisppp_start(&i4bisppp_softc[unit].sc_if);    
719 }
720
721 /*---------------------------------------------------------------------------*
722  *      THIS should be used instead of last_active_time to implement
723  *      an activity timeout mechanism.
724  *
725  *      Sending back the time difference unneccessarily complicates the
726  *      idletime checks in i4b_l4.c. Return the largest time instead.
727  *      That way the code in i4b_l4.c needs only minimal changes.
728  *---------------------------------------------------------------------------*/
729 time_t
730 i4bisppp_idletime(int unit)
731 {
732 #ifdef __NetBSD__
733        return(i4bisppp_softc[unit].sc_cdp->last_active_time);
734 #else
735         struct sppp *sp;
736         sp = (struct sppp *) &i4bisppp_softc[unit];
737
738         return((sp->pp_last_recv < sp->pp_last_sent) ?
739                         sp->pp_last_sent : sp->pp_last_recv);
740 #endif
741 }
742
743 /*---------------------------------------------------------------------------*
744  *      this routine is called from the HSCX interrupt handler
745  *      each time a packet is received or transmitted. It should
746  *      be used to implement an activity timeout mechanism.
747  *---------------------------------------------------------------------------*/
748 static void
749 i4bisppp_activity(int unit, int rxtx)
750 {
751         i4bisppp_softc[unit].sc_cdp->last_active_time = SECOND;
752 }
753
754 /*---------------------------------------------------------------------------*
755  *      return this drivers linktab address
756  *---------------------------------------------------------------------------*/
757 drvr_link_t *
758 i4bisppp_ret_linktab(int unit)
759 {
760         return(&i4bisppp_drvr_linktab[unit]);
761 }
762
763 /*---------------------------------------------------------------------------*
764  *      setup the isdn_linktab for this driver
765  *---------------------------------------------------------------------------*/
766 void
767 i4bisppp_set_linktab(int unit, isdn_link_t *ilt)
768 {
769         isdn_linktab[unit] = ilt;
770 }
771
772 /*---------------------------------------------------------------------------*
773  *      initialize this drivers linktab
774  *---------------------------------------------------------------------------*/
775 static void
776 i4bisppp_init_linktab(int unit)
777 {
778         i4bisppp_drvr_linktab[unit].unit = unit;
779         i4bisppp_drvr_linktab[unit].bch_rx_data_ready = i4bisppp_rx_data_rdy;
780         i4bisppp_drvr_linktab[unit].bch_tx_queue_empty = i4bisppp_tx_queue_empty;
781         i4bisppp_drvr_linktab[unit].bch_activity = i4bisppp_activity;
782         i4bisppp_drvr_linktab[unit].line_connected = i4bisppp_connect;
783         i4bisppp_drvr_linktab[unit].line_disconnected = i4bisppp_disconnect;
784         i4bisppp_drvr_linktab[unit].dial_response = i4bisppp_dialresponse;      
785         i4bisppp_drvr_linktab[unit].updown_ind = i4bisppp_updown;       
786 }
787
788 /*===========================================================================*/