Merge from vendor branch OPENSSH:
[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.9 2004/04/01 07:27:17 joerg 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_arp.h>
68 #include <net/if_types.h>
69 #include <net/sppp/if_sppp.h>
70
71
72 #if defined(__DragonFly__) || (defined(__FreeBSD_version) &&  __FreeBSD_version >= 400008)
73 #include "use_bpf.h"     
74 #else
75 #include "bpfilter.h"
76 #endif
77 #if NBPFILTER > 0 || NBPF > 0
78 #include <sys/time.h>
79 #include <net/bpf.h>
80 #endif
81
82 #if defined(__DragonFly__) || defined(__FreeBSD__)
83 #include <net/i4b/include/machine/i4b_debug.h>
84 #include <net/i4b/include/machine/i4b_ioctl.h>
85 #else
86 #include <i4b/i4b_ioctl.h>
87 #include <i4b/i4b_cause.h>
88 #include <i4b/i4b_debug.h>
89 #endif
90
91 #include "../include/i4b_global.h"
92 #include "../include/i4b_l3l4.h"
93 #include "../layer4/i4b_l4.h"
94
95 #if defined(__DragonFly__) || defined(__FreeBSD__)
96 #define PDEVSTATIC      static
97
98 #ifdef __DragonFly__
99 #define ISPPP_FMT       "%s: "
100 #define ISPPP_ARG(sc)   ((sc)->sc_if.if_xname)
101 #define IFP2UNIT(ifp)   ((struct i4bisppp_softc *)ifp->if_softc)->sc_unit
102 #else
103 #define ISPPP_FMT       "isp%d: "
104 #define ISPPP_ARG(sc)   ((sc)->sc_if.if_unit)
105 #define IFP2UNIT(ifp)   (ifp)->if_unit
106 #endif
107                 
108 # if defined(__DragonFly__) || __FreeBSD_version >= 300001
109 #  define CALLOUT_INIT(chan)            callout_handle_init(chan)
110 #  define TIMEOUT(fun, arg, chan, tick) chan = timeout(fun, arg, tick)
111 #  define UNTIMEOUT(fun, arg, chan)     untimeout(fun, arg, chan)
112 #  define IOCTL_CMD_T u_long
113 # else
114 #  define CALLOUT_INIT(chan)            do {} while(0)
115 #  define TIMEOUT(fun, arg, chan, tick) timeout(fun, arg, tick)
116 #  define UNTIMEOUT(fun, arg, chan)     untimeout(fun, arg)
117 #  define IOCTL_CMD_T int
118 # endif
119
120 #elif defined __NetBSD__ || defined __OpenBSD__
121 #define ISPPP_FMT       "%s: "
122 #define ISPPP_ARG(sc)   ((sc)->sc_if.if_xname)
123 #define PDEVSTATIC      /* not static */
124 #define IOCTL_CMD_T     u_long
125 #define IFP2UNIT(ifp)   ((struct i4bisppp_softc *)ifp->if_softc)->sc_unit
126 #else
127 # error "What system are you using?"
128 #endif
129
130 #if defined(__DragonFly__) || defined(__FreeBSD__)
131 PDEVSTATIC void i4bispppattach(void *);
132 PSEUDO_SET(i4bispppattach, i4b_isppp);
133 #else
134 PDEVSTATIC void i4bispppattach(void);
135 #endif
136
137 #define I4BISPPPACCT            1       /* enable accounting messages */
138 #define I4BISPPPACCTINTVL       2       /* accounting msg interval in secs */
139 #define I4BISPPPDISCDEBUG       1       
140
141 #define PPP_HDRLEN              4       /* 4 octetts PPP header length  */
142
143 struct i4bisppp_softc {
144         /*
145          * struct sppp starts with a struct ifnet, but we gotta allocate
146          * more space for it.  NB: do not relocate this union, it must
147          * be first in isppp_softc.  The tls and tlf hooks below want to
148          * convert a ``struct sppp *'' into a ``struct isppp_softc *''.
149          */
150         union {
151                 struct ifnet scu_if;
152                 struct sppp scu_sp;
153         } sc_if_un;
154 #define sc_if sc_if_un.scu_if
155
156         int     sc_state;       /* state of the interface       */
157
158 #if !defined(__FreeBSD__) || defined(__DragonFly__)
159         int     sc_unit;        /* unit number for Net/OpenBSD  */
160 #endif
161
162         call_desc_t *sc_cdp;    /* ptr to call descriptor       */
163
164 #ifdef I4BISPPPACCT
165         int sc_iinb;            /* isdn driver # of inbytes     */
166         int sc_ioutb;           /* isdn driver # of outbytes    */
167         int sc_inb;             /* # of bytes rx'd              */
168         int sc_outb;            /* # of bytes tx'd              */
169         int sc_linb;            /* last # of bytes rx'd         */
170         int sc_loutb;           /* last # of bytes tx'd         */
171         int sc_fn;              /* flag, first null acct        */
172 #endif
173
174 #if defined(__DragonFly__) || (defined(__FreeBSD_version) && __FreeBSD_version >= 300001)
175         struct callout_handle sc_ch;
176 #endif
177
178 } i4bisppp_softc[NI4BISPPP];
179
180 static void     i4bisppp_init_linktab(int unit);
181 static int      i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data,
182                                struct ucred *cr);
183
184 #if 0
185 static void     i4bisppp_send(struct ifnet *ifp);
186 #endif
187
188 static void     i4bisppp_start(struct ifnet *ifp);
189
190 #if 0 /* never used ??? */
191 static void     i4bisppp_timeout(void *cookie);
192 #endif
193
194 static void     i4bisppp_tls(struct sppp *sp);
195 static void     i4bisppp_tlf(struct sppp *sp);
196 static void     i4bisppp_state_changed(struct sppp *sp, int new_state);
197 static void     i4bisppp_negotiation_complete(struct sppp *sp);
198 static void     i4bisppp_watchdog(struct ifnet *ifp);
199 time_t          i4bisppp_idletime(int unit);
200
201 /* initialized by L4 */
202
203 static drvr_link_t i4bisppp_drvr_linktab[NI4BISPPP];
204 static isdn_link_t *isdn_linktab[NI4BISPPP];
205
206 enum i4bisppp_states {
207         ST_IDLE,                        /* initialized, ready, idle     */
208         ST_DIALING,                     /* dialling out to remote       */
209         ST_CONNECTED,                   /* connected to remote          */
210 };
211
212 /*===========================================================================*
213  *                      DEVICE DRIVER ROUTINES
214  *===========================================================================*/
215
216 /*---------------------------------------------------------------------------*
217  *      interface attach routine at kernel boot time
218  *---------------------------------------------------------------------------*/
219 PDEVSTATIC void
220 #if defined(__DragonFly__) || defined(__FreeBSD__)
221 i4bispppattach(void *dummy)
222 #else
223 i4bispppattach()
224 #endif
225 {
226         struct i4bisppp_softc *sc = i4bisppp_softc;
227         int i;
228
229 #ifndef HACK_NO_PSEUDO_ATTACH_MSG
230 #ifdef SPPP_VJ
231         printf("i4bisppp: %d ISDN SyncPPP device(s) attached (VJ header compression)\n", NI4BISPPP);
232 #else
233         printf("i4bisppp: %d ISDN SyncPPP device(s) attached\n", NI4BISPPP);
234 #endif
235 #endif
236
237         for(i = 0; i < NI4BISPPP; sc++, i++) {
238                 i4bisppp_init_linktab(i);
239                 
240                 sc->sc_if.if_softc = sc;
241
242 #ifdef __DragonFly__
243                 if_initname(&(sc->sc_if), "isp", i);
244 #elif defined(__FreeBSD__)
245                 sc->sc_if.if_name = "isp";
246 #if defined(__FreeBSD_version) && __FreeBSD_version < 300001
247                 sc->sc_if.if_next = NULL;
248 #endif
249                 sc->sc_if.if_unit = i;
250 #else
251                 sprintf(sc->sc_if.if_xname, "isp%d", i);
252                 sc->sc_unit = i;
253 #endif
254
255                 sc->sc_if.if_mtu = PP_MTU;
256
257 #ifdef __NetBSD__
258                 sc->sc_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT |
259                                         IFF_MULTICAST;
260 #else
261                 sc->sc_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT;
262 #endif
263
264                 sc->sc_if.if_type = IFT_ISDNBASIC;
265                 sc->sc_state = ST_IDLE;
266
267                 sc->sc_if.if_ioctl = i4bisppp_ioctl;
268
269                 /* actually initialized by sppp_attach() */
270                 /* sc->sc_if.if_output = sppp_output; */
271
272                 sc->sc_if.if_start = i4bisppp_start;
273
274                 sc->sc_if.if_hdrlen = 0;
275                 sc->sc_if.if_addrlen = 0;
276                 sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
277
278                 sc->sc_if.if_ipackets = 0;
279                 sc->sc_if.if_ierrors = 0;
280                 sc->sc_if.if_opackets = 0;
281                 sc->sc_if.if_oerrors = 0;
282                 sc->sc_if.if_collisions = 0;
283                 sc->sc_if.if_ibytes = 0;
284                 sc->sc_if.if_obytes = 0;
285                 sc->sc_if.if_imcasts = 0;
286                 sc->sc_if.if_omcasts = 0;
287                 sc->sc_if.if_iqdrops = 0;
288                 sc->sc_if.if_noproto = 0;
289
290 #if I4BISPPPACCT
291                 sc->sc_if.if_timer = 0; 
292                 sc->sc_if.if_watchdog = i4bisppp_watchdog;      
293                 sc->sc_iinb = 0;
294                 sc->sc_ioutb = 0;
295                 sc->sc_inb = 0;
296                 sc->sc_outb = 0;
297                 sc->sc_linb = 0;
298                 sc->sc_loutb = 0;
299                 sc->sc_fn = 1;
300 #endif
301
302                 sc->sc_if_un.scu_sp.pp_tls = i4bisppp_tls;
303                 sc->sc_if_un.scu_sp.pp_tlf = i4bisppp_tlf;
304                 sc->sc_if_un.scu_sp.pp_con = i4bisppp_negotiation_complete;
305                 sc->sc_if_un.scu_sp.pp_chg = i4bisppp_state_changed;
306
307                 sppp_attach(&sc->sc_if);
308 /* XXX: validate / add proper code */
309                 ether_ifattach_bpf(&sc->sc_if, ((struct arpcom*)sc)->ac_enaddr,
310                                    DLT_PPP, PPP_HDRLEN);
311                 CALLOUT_INIT(&sc->sc_ch);
312         }
313 }
314
315 /*---------------------------------------------------------------------------*
316  *      process ioctl
317  *---------------------------------------------------------------------------*/
318 static int
319 i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data,
320                struct ucred *cr)
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 #if defined(__DragonFly__) || defined(__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 #if defined(__DragonFly__) || defined(__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 /*===========================================================================*/