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