proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[dragonfly.git] / sys / net / i4b / driver / i4b_ipr.c
1 /*
2  * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *      i4b_ipr.c - isdn4bsd IP over raw HDLC ISDN network driver
28  *      ---------------------------------------------------------
29  *
30  * $FreeBSD: src/sys/i4b/driver/i4b_ipr.c,v 1.8.2.3 2001/10/27 15:48:17 hm Exp $
31  * $DragonFly: src/sys/net/i4b/driver/i4b_ipr.c,v 1.3 2003/06/25 03:55:55 dillon Exp $
32  *
33  *      last edit-date: [Fri Oct 26 19:32:38 2001]
34  *
35  *---------------------------------------------------------------------------*
36  *
37  *      statistics counter usage (interface lifetime):
38  *      ----------------------------------------------
39  *      sc->sc_if.if_ipackets   # of received packets
40  *      sc->sc_if.if_ierrors    # of error packets not going to upper layers
41  *      sc->sc_if.if_opackets   # of transmitted packets
42  *      sc->sc_if.if_oerrors    # of error packets not being transmitted
43  *      sc->sc_if.if_collisions # of invalid ip packets after VJ decompression
44  *      sc->sc_if.if_ibytes     # of bytes coming in from the line (before VJ)
45  *      sc->sc_if.if_obytes     # of bytes going out to the line (after VJ)
46  *      sc->sc_if.if_imcasts      (currently unused)
47  *      sc->sc_if.if_omcasts    # of frames sent out of the fastqueue
48  *      sc->sc_if.if_iqdrops    # of frames dropped on input because queue full
49  *      sc->sc_if.if_noproto    # of frames dropped on output because !AF_INET
50  *
51  *      statistics counter usage (connection lifetime):
52  *      -----------------------------------------------
53  *      sc->sc_iinb             # of ISDN incoming bytes from HSCX
54  *      sc->sc_ioutb            # of ISDN outgoing bytes from HSCX
55  *      sc->sc_inb              # of incoming bytes after decompression
56  *      sc->sc_outb             # of outgoing bytes before compression
57  *
58  *---------------------------------------------------------------------------*/ 
59
60 #include "i4bipr.h"
61
62 #if NI4BIPR > 0
63
64 #ifdef __FreeBSD__
65 #include "opt_i4b.h"
66 #endif
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/mbuf.h>
71 #include <sys/socket.h>
72 #include <sys/errno.h>
73
74 #if defined(__FreeBSD__)
75 #include <sys/ioccom.h>
76 #include <sys/sockio.h>
77 #ifdef IPR_VJ
78 #include <sys/malloc.h>
79 #endif
80 #else
81 #include <sys/ioctl.h>
82 #endif
83
84 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
85 #include <sys/callout.h>
86 #endif
87
88 #include <sys/kernel.h>
89
90 #include <net/if.h>
91 #include <net/if_types.h>
92 #include <net/netisr.h>
93
94 #include <netinet/in.h>
95 #include <netinet/in_systm.h>
96 #include <netinet/in_var.h>
97 #include <netinet/ip.h>
98
99 #ifdef IPR_VJ
100 #include <net/slcompress.h>       
101 #define IPR_COMPRESS IFF_LINK0  /* compress TCP traffic */
102 #define IPR_AUTOCOMP IFF_LINK1  /* auto-enable TCP compression */
103
104 /*---------------------------------------------------------------------------
105  * NOTICE: using NO separate buffer relies on the assumption, that the HSCX
106  * IRQ handler _always_ allocates a single, continuous mbuf cluster large
107  * enough to hold the maximum MTU size if the ipr interface !
108  *
109  * CAUTION: i have re-defined IPR_VJ_USEBUFFER because it makes problems
110  *          with 2 i4b's back to back running cvs over ssh, cvs simply
111  *          aborts because it gets bad data. Everything else (telnet/ftp?etc)
112  *          functions fine. 
113  *---------------------------------------------------------------------------*/
114 #define IPR_VJ_USEBUFFER        /* define to use an allocated separate buffer*/
115                                 /* undef to uncompress in the mbuf itself    */
116 #endif /* IPR_VJ */
117
118 #if defined(__FreeBSD_version) &&  __FreeBSD_version >= 400008
119 #include "bpf.h"
120 #else
121 #include "bpfilter.h"
122 #endif
123
124 #if NBPFILTER > 0 || NBPF > 0
125 #include <sys/time.h>
126 #include <net/bpf.h>
127 #endif
128
129 #ifdef __FreeBSD__
130 #include <machine/i4b_ioctl.h>
131 #include <machine/i4b_debug.h>
132 #else
133 #include <i4b/i4b_debug.h>
134 #include <i4b/i4b_ioctl.h>
135 #endif
136
137 #include <i4b/include/i4b_global.h>
138 #include <i4b/include/i4b_l3l4.h>
139
140 #include <i4b/layer4/i4b_l4.h>
141
142 #ifndef __FreeBSD__
143 #include <machine/cpu.h> /* For softnet */
144 #endif
145
146 #ifdef __FreeBSD__
147 #define IPR_FMT "ipr%d: "
148 #define IPR_ARG(sc)     ((sc)->sc_if.if_unit)
149 #define PDEVSTATIC      static
150 #elif defined(__bsdi__)
151 #define IPR_FMT "ipr%d: "
152 #define IPR_ARG(sc)     ((sc)->sc_if.if_unit)
153 #define PDEVSTATIC      /* not static */
154 #else
155 #define IPR_FMT "%s: "
156 #define IPR_ARG(sc)     ((sc)->sc_if.if_xname)
157 #define PDEVSTATIC      /* not static */
158 #endif
159
160 #define I4BIPRMTU       1500            /* regular MTU */
161 #define I4BIPRMAXMTU    2000            /* max MTU */
162 #define I4BIPRMINMTU    500             /* min MTU */
163
164 #define I4BIPRMAXQLEN   50              /* max queue length */
165
166 #define I4BIPRACCT      1               /* enable accounting messages */
167 #define I4BIPRACCTINTVL 2               /* accounting msg interval in secs */
168 #define I4BIPRADJFRXP   1               /* adjust 1st rxd packet */
169
170 /* initialized by L4 */
171
172 static drvr_link_t ipr_drvr_linktab[NI4BIPR];
173 static isdn_link_t *isdn_linktab[NI4BIPR];
174
175 struct ipr_softc {
176         struct ifnet    sc_if;          /* network-visible interface    */
177         int             sc_state;       /* state of the interface       */
178
179 #ifndef __FreeBSD__
180         int             sc_unit;        /* unit number for Net/OpenBSD  */
181 #endif
182
183         call_desc_t     *sc_cdp;        /* ptr to call descriptor       */
184         int             sc_updown;      /* soft state of interface      */
185         struct ifqueue  sc_fastq;       /* interactive traffic          */
186         int             sc_dialresp;    /* dialresponse                 */
187         int             sc_lastdialresp;/* last dialresponse            */
188         
189 #if I4BIPRACCT
190         int             sc_iinb;        /* isdn driver # of inbytes     */
191         int             sc_ioutb;       /* isdn driver # of outbytes    */
192         int             sc_inb;         /* # of bytes rx'd              */
193         int             sc_outb;        /* # of bytes tx'd              */
194         int             sc_linb;        /* last # of bytes rx'd         */
195         int             sc_loutb;       /* last # of bytes tx'd         */
196         int             sc_fn;          /* flag, first null acct        */
197 #endif  
198
199 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
200         struct callout  sc_callout;
201 #endif
202 #if defined(__FreeBSD__)
203         struct callout_handle   sc_callout;
204 #endif
205
206 #ifdef I4BIPRADJFRXP
207         int             sc_first_pkt;   /* flag, first rxd packet       */
208 #endif
209 #if IPR_LOG
210         int             sc_log_first;   /* log first n packets          */
211 #endif
212
213 #ifdef IPR_VJ
214         struct slcompress sc_compr;     /* tcp compression data         */
215 #ifdef IPR_VJ_USEBUFFER
216         u_char          *sc_cbuf;       /* tcp decompression buffer     */
217 #endif
218 #endif
219
220 } ipr_softc[NI4BIPR];
221
222 enum ipr_states {
223         ST_IDLE,                        /* initialized, ready, idle     */
224         ST_DIALING,                     /* dialling out to remote       */
225         ST_CONNECTED_W,                 /* connected to remote          */
226         ST_CONNECTED_A,                 /* connected to remote          */
227 };
228
229 #if defined(__FreeBSD__) || defined(__bsdi__)
230 #define THE_UNIT        sc->sc_if.if_unit
231 #else
232 #define THE_UNIT        sc->sc_unit
233 #endif
234
235 #if defined __FreeBSD__ || defined __NetBSD__
236 #  define IOCTL_CMD_T u_long
237 #else
238 #  define IOCTL_CMD_T int
239 #endif
240
241 #ifdef __FreeBSD__
242 PDEVSTATIC void i4biprattach(void *);
243 PSEUDO_SET(i4biprattach, i4b_ipr);
244 static int i4biprioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data);
245 #else
246 PDEVSTATIC void i4biprattach __P((void));
247 static int i4biprioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
248 #endif
249
250 #ifdef __bsdi__
251 static int iprwatchdog(int unit);
252 #else
253 static void iprwatchdog(struct ifnet *ifp);
254 #endif
255 static void ipr_init_linktab(int unit);
256 static void ipr_tx_queue_empty(int unit);
257 static int i4biproutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rtp);
258 static void iprclearqueues(struct ipr_softc *sc);
259
260 /*===========================================================================*
261  *                      DEVICE DRIVER ROUTINES
262  *===========================================================================*/
263
264 /*---------------------------------------------------------------------------*
265  *      interface attach routine at kernel boot time
266  *---------------------------------------------------------------------------*/
267 PDEVSTATIC void
268 #ifdef __FreeBSD__
269 i4biprattach(void *dummy)
270 #else
271 i4biprattach()
272 #endif
273 {
274         struct ipr_softc *sc = ipr_softc;
275         int i;
276
277 #ifdef IPR_VJ
278         printf("i4bipr: %d IP over raw HDLC ISDN device(s) attached (VJ header compression)\n", NI4BIPR);
279 #else
280         printf("i4bipr: %d IP over raw HDLC ISDN device(s) attached\n", NI4BIPR);
281 #endif
282         
283         for(i=0; i < NI4BIPR; sc++, i++)
284         {
285                 ipr_init_linktab(i);
286
287                 NDBGL4(L4_DIALST, "setting dial state to ST_IDLE");
288
289                 sc->sc_state = ST_IDLE;
290                 
291 #ifdef __FreeBSD__              
292                 sc->sc_if.if_name = "ipr";
293                 sc->sc_if.if_unit = i;
294 #elif defined(__bsdi__)
295                 sc->sc_if.if_name = "ipr";
296                 sc->sc_if.if_unit = i;
297 #else
298                 sprintf(sc->sc_if.if_xname, "ipr%d", i);
299                 sc->sc_if.if_softc = sc;
300                 sc->sc_unit = i;
301 #endif
302
303 #ifdef  IPR_VJ
304                 sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_SIMPLEX | IPR_AUTOCOMP;
305 #else
306                 sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_SIMPLEX;
307 #endif
308
309 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
310                 callout_init(&sc->sc_callout);
311 #endif
312
313                 sc->sc_if.if_mtu = I4BIPRMTU;
314                 sc->sc_if.if_type = IFT_ISDNBASIC;
315                 sc->sc_if.if_ioctl = i4biprioctl;
316                 sc->sc_if.if_output = i4biproutput;
317
318                 sc->sc_if.if_snd.ifq_maxlen = I4BIPRMAXQLEN;
319                 sc->sc_fastq.ifq_maxlen = I4BIPRMAXQLEN;
320
321 #if defined (__FreeBSD__) && __FreeBSD__ > 4
322                 mtx_init(&sc->sc_fastq.ifq_mtx, "i4b_ipr_fastq", MTX_DEF);
323 #endif          
324                 sc->sc_if.if_ipackets = 0;
325                 sc->sc_if.if_ierrors = 0;
326                 sc->sc_if.if_opackets = 0;
327                 sc->sc_if.if_oerrors = 0;
328                 sc->sc_if.if_collisions = 0;
329                 sc->sc_if.if_ibytes = 0;
330                 sc->sc_if.if_obytes = 0;
331                 sc->sc_if.if_imcasts = 0;
332                 sc->sc_if.if_omcasts = 0;
333                 sc->sc_if.if_iqdrops = 0;
334                 sc->sc_if.if_noproto = 0;
335
336 #if I4BIPRACCT
337                 sc->sc_if.if_timer = 0; 
338                 sc->sc_if.if_watchdog = iprwatchdog;    
339                 sc->sc_iinb = 0;
340                 sc->sc_ioutb = 0;
341                 sc->sc_inb = 0;
342                 sc->sc_outb = 0;
343                 sc->sc_linb = 0;
344                 sc->sc_loutb = 0;
345                 sc->sc_fn = 1;
346 #endif
347 #if IPR_LOG
348                 sc->sc_log_first = IPR_LOG;
349 #endif
350
351 #ifdef  IPR_VJ
352 #ifdef __FreeBSD__
353                 sl_compress_init(&sc->sc_compr, -1);
354 #else
355                 sl_compress_init(&sc->sc_compr);
356 #endif
357
358 #ifdef IPR_VJ_USEBUFFER
359                 if(!((sc->sc_cbuf =
360                    (u_char *)malloc(I4BIPRMAXMTU+128, M_DEVBUF, M_WAITOK))))
361                 {
362                         panic("if_ipr.c, ipr_attach: VJ malloc failed");
363                 }
364 #endif
365 #endif
366                 sc->sc_updown = SOFT_ENA;       /* soft enabled */
367                 sc->sc_dialresp = DSTAT_NONE;   /* no response */
368                 sc->sc_lastdialresp = DSTAT_NONE;
369                 
370                 if_attach(&sc->sc_if);
371
372 #if NBPFILTER > 0 || NBPF > 0
373 #ifdef __FreeBSD__
374                 bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
375 #else
376                 bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_NULL, sizeof(u_int));
377 #endif
378 #endif          
379         }
380 }
381
382 /*---------------------------------------------------------------------------*
383  *      output a packet to the ISDN B-channel
384  *---------------------------------------------------------------------------*/
385 static int
386 i4biproutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
387          struct rtentry *rtp)
388 {
389         struct ipr_softc *sc;
390         int unit;
391         int s;
392         struct ifqueue *ifq;
393         struct ip *ip;
394         
395         s = SPLI4B();
396
397 #if defined(__FreeBSD__) || defined(__bsdi__)
398         unit = ifp->if_unit;
399         sc = &ipr_softc[unit];
400 #else
401         sc = ifp->if_softc;
402         unit = sc->sc_unit;
403 #endif
404
405         /* check for IP */
406         
407         if(dst->sa_family != AF_INET)
408         {
409                 printf(IPR_FMT "af%d not supported\n", IPR_ARG(sc), dst->sa_family);
410                 m_freem(m);
411                 splx(s);
412                 sc->sc_if.if_noproto++;
413                 sc->sc_if.if_oerrors++;
414                 return(EAFNOSUPPORT);
415         }
416
417         /* check interface state = UP */
418         
419         if(!(ifp->if_flags & IFF_UP))
420         {
421                 NDBGL4(L4_IPRDBG, "ipr%d: interface is DOWN!", unit);
422                 m_freem(m);
423                 splx(s);
424                 sc->sc_if.if_oerrors++;
425                 return(ENETDOWN);
426         }
427
428         /* dial if necessary */
429         
430         if(sc->sc_state == ST_IDLE || sc->sc_state == ST_DIALING)
431         {
432
433 #ifdef NOTDEF
434                 switch(sc->sc_dialresp)
435                 {
436                         case DSTAT_TFAIL:       /* transient failure */
437                                 NDBGL4(L4_IPRDBG, "ipr%d: transient dial failure!", unit);
438                                 m_freem(m);
439                                 iprclearqueues(sc);
440                                 sc->sc_dialresp = DSTAT_NONE;
441                                 splx(s);
442                                 sc->sc_if.if_oerrors++;
443                                 return(ENETUNREACH);
444                                 break;
445
446                         case DSTAT_PFAIL:       /* permanent failure */
447                                 NDBGL4(L4_IPRDBG, "ipr%d: permanent dial failure!", unit);
448                                 m_freem(m);
449                                 iprclearqueues(sc);
450                                 sc->sc_dialresp = DSTAT_NONE;
451                                 splx(s);
452                                 sc->sc_if.if_oerrors++;
453                                 return(EHOSTUNREACH);                           
454                                 break;
455
456                         case DSTAT_INONLY:      /* no dialout allowed*/
457                                 NDBGL4(L4_IPRDBG, "ipr%d: dialout not allowed failure!", unit);
458                                 m_freem(m);
459                                 iprclearqueues(sc);
460                                 sc->sc_dialresp = DSTAT_NONE;
461                                 splx(s);
462                                 sc->sc_if.if_oerrors++;
463                                 return(EHOSTUNREACH);                           
464                                 break;
465                 }
466 #endif
467
468                 NDBGL4(L4_IPRDBG, "ipr%d: send dial request message!", unit);
469                 NDBGL4(L4_DIALST, "ipr%d: setting dial state to ST_DIALING", unit);
470                 i4b_l4_dialout(BDRV_IPR, unit);
471                 sc->sc_state = ST_DIALING;
472         }
473
474 #if IPR_LOG
475         if(sc->sc_log_first > 0)
476         {
477                 --(sc->sc_log_first);
478                 i4b_l4_packet_ind(BDRV_IPR, unit, 1, m );
479         }
480 #endif
481
482         /* update access time */
483         
484         microtime(&sc->sc_if.if_lastchange);
485
486         /*
487          * check, if type of service indicates interactive, i.e. telnet,
488          * traffic. in case it is interactive, put it into the fast queue,
489          * else (i.e. ftp traffic) put it into the "normal" queue
490          */
491
492         ip = mtod(m, struct ip *);              /* get ptr to ip header */
493          
494         if(ip->ip_tos & IPTOS_LOWDELAY)
495                 ifq = &sc->sc_fastq;
496         else
497                 ifq = &sc->sc_if.if_snd;
498
499         /* check for space in choosen send queue */
500         
501 #if defined (__FreeBSD__) && __FreeBSD__ > 4
502         if(! IF_HANDOFF(ifq, m, NULL))
503         {
504                 NDBGL4(L4_IPRDBG, "ipr%d: send queue full!", unit);
505                 splx(s);
506                 sc->sc_if.if_oerrors++;
507                 return(ENOBUFS);
508         }
509 #else
510         if(IF_QFULL(ifq))
511         {
512                 NDBGL4(L4_IPRDBG, "ipr%d: send queue full!", unit);
513                 IF_DROP(ifq);
514                 m_freem(m);
515                 splx(s);
516                 sc->sc_if.if_oerrors++;
517                 return(ENOBUFS);
518         }       
519
520         IF_ENQUEUE(ifq, m);
521 #endif
522         
523         NDBGL4(L4_IPRDBG, "ipr%d: add packet to send queue!", unit);
524         
525         ipr_tx_queue_empty(unit);
526
527         splx(s);
528
529         return (0);
530 }
531
532 /*---------------------------------------------------------------------------*
533  *      process ioctl
534  *---------------------------------------------------------------------------*/
535 #ifdef __FreeBSD__
536 static int
537 i4biprioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data)
538 #else
539 static int
540 i4biprioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
541 #endif
542 {
543 #if defined(__FreeBSD__) || defined(__bsdi__)
544         struct ipr_softc *sc = &ipr_softc[ifp->if_unit];
545 #else
546         struct ipr_softc *sc = ifp->if_softc;
547 #endif
548
549         struct ifreq *ifr = (struct ifreq *)data;
550         struct ifaddr *ifa = (struct ifaddr *)data;
551         int s;
552         int error = 0;
553
554         s = SPLI4B();
555         
556         switch (cmd)
557         {
558                 case SIOCAIFADDR:       /* add interface address */
559                 case SIOCSIFADDR:       /* set interface address */
560                 case SIOCSIFDSTADDR:    /* set interface destination address */
561                         if(ifa->ifa_addr->sa_family != AF_INET)
562                                 error = EAFNOSUPPORT;
563                         else
564                                 sc->sc_if.if_flags |= IFF_UP;
565                         microtime(&sc->sc_if.if_lastchange);
566                         break;
567
568                 case SIOCSIFFLAGS:      /* set interface flags */
569                         if(!(ifr->ifr_flags & IFF_UP))
570                         {
571                                 if(sc->sc_if.if_flags & IFF_RUNNING)
572                                 {
573                                         /* disconnect ISDN line */
574 #if defined(__FreeBSD__) || defined(__bsdi__)
575                                         i4b_l4_drvrdisc(BDRV_IPR, ifp->if_unit);
576 #else
577                                         i4b_l4_drvrdisc(BDRV_IPR, sc->sc_unit);
578 #endif
579                                         sc->sc_if.if_flags &= ~IFF_RUNNING;
580                                 }
581
582                                 sc->sc_state = ST_IDLE;
583
584                                 /* empty queues */
585
586                                 iprclearqueues(sc);
587                         }
588
589                         if(ifr->ifr_flags & IFF_DEBUG)
590                         {
591                                 /* enable debug messages */
592                         }
593                         
594                         microtime(&sc->sc_if.if_lastchange);
595                         break;
596
597 #if !defined(__OpenBSD__)                       
598                 case SIOCSIFMTU:        /* set interface MTU */
599                         if(ifr->ifr_mtu > I4BIPRMAXMTU)
600                                 error = EINVAL;
601                         else if(ifr->ifr_mtu < I4BIPRMINMTU)
602                                 error = EINVAL;
603                         else
604                         {
605                                 ifp->if_mtu = ifr->ifr_mtu;
606                                 microtime(&sc->sc_if.if_lastchange);
607                         }
608                         break;
609 #endif /* __OPENBSD__ */
610
611 #if 0
612         /* not needed for FreeBSD, done in sl_compress_init() (-hm) */
613         
614                         /* need to add an ioctl:        set VJ max slot ID
615                          * #define IPRIOCSMAXCID        _IOW('I', XXX, int)
616                          */
617 #ifdef IPR_VJ
618                 case IPRIOCSMAXCID:
619                         {
620                         struct thread *td = curthread;  /* XXX */
621
622 #if defined(__FreeBSD_version) && __FreeBSD_version >= 400005
623                         if ((error = suser(td)) != 0)
624                                 return (error);
625                         sl_compress_setup(sc->sc_compr, *(int *)data);
626                         }
627                         break;
628 #endif
629 #endif
630                 default:
631                         error = EINVAL;
632                         break;
633         }
634
635         splx(s);
636
637         return(error);
638 }
639
640 /*---------------------------------------------------------------------------*
641  *      clear the interface's send queues
642  *---------------------------------------------------------------------------*/
643 static void
644 iprclearqueues(struct ipr_softc *sc)
645 {
646         int x;
647
648 #if defined (__FreeBSD__) && __FreeBSD__ > 4
649         x = splimp();
650         IF_DRAIN(&sc->sc_fastq);
651         IF_DRAIN(&sc->sc_if.if_snd);
652         splx(x);
653 #else
654         struct mbuf *m;
655
656         for(;;)
657         {
658                 x = splimp();
659                 IF_DEQUEUE(&sc->sc_fastq, m);
660                 splx(x);
661                 if(m)
662                         m_freem(m);
663                 else
664                         break;
665         }
666
667         for(;;)
668         {
669                 x = splimp();
670                 IF_DEQUEUE(&sc->sc_if.if_snd, m);
671                 splx(x);
672                 if(m)
673                         m_freem(m);
674                 else
675                         break;
676         }
677 #endif
678 }
679         
680 #if I4BIPRACCT
681 /*---------------------------------------------------------------------------*
682  *      watchdog routine
683  *---------------------------------------------------------------------------*/
684 #ifdef __bsdi__
685 static int
686 iprwatchdog(int unit)
687 {
688 #else
689 static void
690 iprwatchdog(struct ifnet *ifp)
691 {
692 #endif
693 #ifdef __FreeBSD__
694         int unit = ifp->if_unit;
695         struct ipr_softc *sc = &ipr_softc[unit];
696 #elif defined(__bsdi__)
697         struct ipr_softc *sc = &ipr_softc[unit];
698         struct ifnet *ifp = &ipr_softc[unit].sc_if;
699 #else
700         struct ipr_softc *sc = ifp->if_softc;
701         int unit = sc->sc_unit;
702 #endif
703         bchan_statistics_t bs;
704         
705         /* get # of bytes in and out from the HSCX driver */ 
706         
707         (*isdn_linktab[unit]->bch_stat)
708                 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
709
710         sc->sc_ioutb += bs.outbytes;
711         sc->sc_iinb += bs.inbytes;
712         
713         if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) 
714         {
715                 int ri = (sc->sc_iinb - sc->sc_linb)/I4BIPRACCTINTVL;
716                 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BIPRACCTINTVL;
717
718                 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
719                         sc->sc_fn = 0;
720                 else
721                         sc->sc_fn = 1;
722                         
723                 sc->sc_linb = sc->sc_iinb;
724                 sc->sc_loutb = sc->sc_ioutb;
725
726                 i4b_l4_accounting(BDRV_IPR, unit, ACCT_DURING,
727                          sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb);
728         }
729         sc->sc_if.if_timer = I4BIPRACCTINTVL;   
730 #ifdef __bsdi__
731         return 0;
732 #endif
733 }
734 #endif /* I4BIPRACCT */
735
736 /*===========================================================================*
737  *                      ISDN INTERFACE ROUTINES
738  *===========================================================================*/
739
740 /*---------------------------------------------------------------------------*
741  *      start transmitting after connect
742  *---------------------------------------------------------------------------*/
743 static void
744 i4bipr_connect_startio(struct ipr_softc *sc)
745 {
746         int s = SPLI4B();
747         
748         if(sc->sc_state == ST_CONNECTED_W)
749         {
750                 sc->sc_state = ST_CONNECTED_A;
751                 ipr_tx_queue_empty(THE_UNIT);
752         }
753
754         splx(s);
755 }
756  
757 /*---------------------------------------------------------------------------*
758  *      this routine is called from L4 handler at connect time
759  *---------------------------------------------------------------------------*/
760 static void
761 ipr_connect(int unit, void *cdp)
762 {
763         struct ipr_softc *sc = &ipr_softc[unit];
764         int s;
765
766         sc->sc_cdp = (call_desc_t *)cdp;
767
768         s = SPLI4B();
769
770         NDBGL4(L4_DIALST, "ipr%d: setting dial state to ST_CONNECTED", unit);
771
772         sc->sc_if.if_flags |= IFF_RUNNING;
773         sc->sc_state = ST_CONNECTED_W;
774
775         sc->sc_dialresp = DSTAT_NONE;
776         sc->sc_lastdialresp = DSTAT_NONE;       
777         
778 #if I4BIPRACCT
779         sc->sc_iinb = 0;
780         sc->sc_ioutb = 0;
781         sc->sc_inb = 0;
782         sc->sc_outb = 0;
783         sc->sc_linb = 0;
784         sc->sc_loutb = 0;
785         sc->sc_if.if_timer = I4BIPRACCTINTVL;
786 #endif
787
788 #ifdef I4BIPRADJFRXP
789         sc->sc_first_pkt = 1;
790 #endif
791
792         /*
793          * Sometimes ISDN B-channels are switched thru asymmetic. This
794          * means that under such circumstances B-channel data (the first
795          * three packets of a TCP connection in my case) may get lost,
796          * causing a large delay until the connection is started.
797          * When the sending of the very first packet of a TCP connection
798          * is delayed for a to be empirically determined delay (close
799          * to a second in my case) those packets go thru and the TCP
800          * connection comes up "almost" immediately (-hm).
801          */
802
803         if(sc->sc_cdp->isdntxdelay > 0)
804         {
805                 int delay;
806
807                 if (hz == 100) {
808                         delay = sc->sc_cdp->isdntxdelay;        /* avoid any rounding */
809                 } else {
810                         delay = sc->sc_cdp->isdntxdelay*hz;
811                         delay /= 100;
812                 }
813
814                 START_TIMER(sc->sc_callout, (TIMEOUT_FUNC_T)i4bipr_connect_startio, (void *)sc,  delay);
815         }
816         else
817         {
818                 sc->sc_state = ST_CONNECTED_A;
819                 ipr_tx_queue_empty(unit);
820         }
821
822         splx(s);
823
824         /* we don't need any negotiation - pass event back right now */
825         i4b_l4_negcomplete(sc->sc_cdp);
826 }
827         
828 /*---------------------------------------------------------------------------*
829  *      this routine is called from L4 handler at disconnect time
830  *---------------------------------------------------------------------------*/
831 static void
832 ipr_disconnect(int unit, void *cdp)
833 {
834         call_desc_t *cd = (call_desc_t *)cdp;
835         struct ipr_softc *sc = &ipr_softc[unit];
836
837         /* new stuff to check that the active channel is being closed */
838
839         if (cd != sc->sc_cdp)
840         {
841                 NDBGL4(L4_IPRDBG, "ipr%d: channel %d not active",
842                                 cd->driver_unit, cd->channelid);
843                 return;
844         }
845
846 #if I4BIPRACCT
847         sc->sc_if.if_timer = 0;
848 #endif
849 #if IPR_LOG
850         /* show next IPR_LOG packets again */
851         sc->sc_log_first = IPR_LOG;
852 #endif
853
854         i4b_l4_accounting(BDRV_IPR, cd->driver_unit, ACCT_FINAL,
855                  sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb);
856         
857         sc->sc_cdp = (call_desc_t *)0;  
858
859         NDBGL4(L4_DIALST, "setting dial state to ST_IDLE");
860
861         sc->sc_dialresp = DSTAT_NONE;
862         sc->sc_lastdialresp = DSTAT_NONE;       
863
864         sc->sc_if.if_flags &= ~IFF_RUNNING;
865         sc->sc_state = ST_IDLE;
866 }
867
868 /*---------------------------------------------------------------------------*
869  *      this routine is used to give a feedback from userland daemon
870  *      in case of dial problems
871  *---------------------------------------------------------------------------*/
872 static void
873 ipr_dialresponse(int unit, int status, cause_t cause)
874 {
875         struct ipr_softc *sc = &ipr_softc[unit];
876         sc->sc_dialresp = status;
877
878         NDBGL4(L4_IPRDBG, "ipr%d: last=%d, this=%d",
879                 unit, sc->sc_lastdialresp, sc->sc_dialresp);
880
881         if(status != DSTAT_NONE)
882         {
883                 NDBGL4(L4_IPRDBG, "ipr%d: clearing queues", unit);
884                 iprclearqueues(sc);
885         }
886 }
887         
888 /*---------------------------------------------------------------------------*
889  *      interface soft up/down
890  *---------------------------------------------------------------------------*/
891 static void
892 ipr_updown(int unit, int updown)
893 {
894         struct ipr_softc *sc = &ipr_softc[unit];
895         sc->sc_updown = updown;
896 }
897         
898 /*---------------------------------------------------------------------------*
899  *      this routine is called from the HSCX interrupt handler
900  *      when a new frame (mbuf) has been received and was put on
901  *      the rx queue. It is assumed that this routines runs at
902  *      pri level splimp() ! Keep it short !
903  *---------------------------------------------------------------------------*/
904 static void
905 ipr_rx_data_rdy(int unit)
906 {
907         register struct ipr_softc *sc = &ipr_softc[unit];
908         register struct mbuf *m;
909 #ifdef IPR_VJ
910 #ifdef IPR_VJ_USEBUFFER
911         u_char *cp = sc->sc_cbuf;
912 #endif  
913         int len, c;
914 #endif
915         
916         if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
917                 return;
918
919         m->m_pkthdr.rcvif = &sc->sc_if;
920
921         m->m_pkthdr.len = m->m_len;
922
923         microtime(&sc->sc_if.if_lastchange);
924
925 #ifdef I4BIPRADJFRXP
926
927         /*
928          * The very first packet after the B channel is switched thru
929          * has very often several bytes of random data prepended. This
930          * routine looks where the IP header starts and removes the
931          * the bad data.
932          */
933
934         if(sc->sc_first_pkt)
935         {
936                 unsigned char *mp = m->m_data;
937                 int i;
938                 
939                 sc->sc_first_pkt = 0;
940
941                 for(i = 0; i < m->m_len; i++, mp++)
942                 {
943                         if( ((*mp & 0xf0) == 0x40) &&
944                             ((*mp & 0x0f) >= 0x05) )
945                         {
946                                 m->m_data = mp;
947                                 m->m_pkthdr.len -= i;                           
948                                 break;
949                         }
950                 }
951         }
952 #endif
953                 
954         sc->sc_if.if_ipackets++;
955         sc->sc_if.if_ibytes += m->m_pkthdr.len;
956
957 #ifdef  IPR_VJ
958         if((c = (*(mtod(m, u_char *)) & 0xf0)) != (IPVERSION << 4))
959         {
960                 /* copy data to buffer */
961
962                 len = m->m_len;
963
964 #ifdef IPR_VJ_USEBUFFER
965 /* XXX */       m_copydata(m, 0, len, cp);
966 #endif
967                 
968                 if(c & 0x80)
969                 {
970                         c = TYPE_COMPRESSED_TCP;
971                 }
972                 else if(c == TYPE_UNCOMPRESSED_TCP)
973                 {
974 #ifdef IPR_VJ_USEBUFFER
975                         *cp &= 0x4f;            /* XXX */
976 #else
977                         *(mtod(m, u_char *)) &= 0x4f;                   
978 #endif                  
979                 }
980
981                 /*
982                  * We've got something that's not an IP packet.
983                  * If compression is enabled, try to decompress it.
984                  * Otherwise, if `auto-enable' compression is on and
985                  * it's a reasonable packet, decompress it and then
986                  * enable compression.  Otherwise, drop it.
987                  */
988                 if(sc->sc_if.if_flags & IPR_COMPRESS)
989                 {
990 #ifdef IPR_VJ_USEBUFFER
991                         len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
992 #else
993                         len = sl_uncompress_tcp((u_char **)&m->m_data, len,
994                                         (u_int)c, &sc->sc_compr);
995 #endif                  
996
997                         if(len <= 0)
998                         {
999 #ifdef DEBUG_IPR_VJ
1000                                 printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_COMPRESS!\n");
1001 #endif
1002                                 goto error;
1003                         }
1004                 }
1005                 else if((sc->sc_if.if_flags & IPR_AUTOCOMP) &&
1006                         (c == TYPE_UNCOMPRESSED_TCP) && (len >= 40))
1007                 {
1008 #ifdef IPR_VJ_USEBUFFER
1009                         len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
1010 #else
1011                         len = sl_uncompress_tcp((u_char **)&m->m_data, len,
1012                                         (u_int)c, &sc->sc_compr);
1013 #endif
1014
1015                         if(len <= 0)
1016                         {
1017 #ifdef DEBUG_IPR_VJ
1018                                 printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_AUTOCOMP!\n");
1019 #endif
1020                                 goto error;
1021                         }
1022
1023                         sc->sc_if.if_flags |= IPR_COMPRESS;
1024                 }
1025                 else
1026                 {
1027 #ifdef DEBUG_IPR_VJ
1028                         printf("i4b_ipr, ipr_input: invalid ip packet!\n");
1029 #endif
1030
1031 error:
1032                         sc->sc_if.if_ierrors++;
1033                         sc->sc_if.if_collisions++;
1034                         m_freem(m);
1035                         return;
1036                 }
1037 #ifdef IPR_VJ_USEBUFFER
1038 /* XXX */       m_copyback(m, 0, len, cp);
1039 #else
1040                 m->m_len = m->m_pkthdr.len = len;
1041 #endif
1042         }
1043 #endif
1044
1045 #if I4BIPRACCT
1046         /* NB. do the accounting after decompression!           */
1047         sc->sc_inb += m->m_pkthdr.len;
1048 #endif
1049 #if IPR_LOG
1050         if(sc->sc_log_first > 0)
1051         {
1052                 --(sc->sc_log_first);
1053                 i4b_l4_packet_ind(BDRV_IPR, unit, 0, m );
1054         }
1055 #endif
1056
1057 #if NBPFILTER > 0 || NBPF > 0
1058         if(sc->sc_if.if_bpf)
1059         {
1060                 /* prepend the address family as a four byte field */           
1061                 struct mbuf mm;
1062                 u_int af = AF_INET;
1063                 mm.m_next = m;
1064                 mm.m_len = 4;
1065                 mm.m_data = (char *)&af;
1066
1067 #ifdef __FreeBSD__
1068                 bpf_mtap(&sc->sc_if, &mm);
1069 #else
1070                 bpf_mtap(sc->sc_if.if_bpf, &mm);
1071 #endif
1072         }
1073 #endif /* NBPFILTER > 0  || NBPF > 0 */
1074
1075 #if defined (__FreeBSD__) && __FreeBSD__ > 4
1076         if(! IF_HANDOFF(&ipintrq, m, NULL))
1077         {
1078                 NDBGL4(L4_IPRDBG, "ipr%d: ipintrq full!", unit);
1079                 sc->sc_if.if_ierrors++;
1080                 sc->sc_if.if_iqdrops++;         
1081         }
1082         else
1083         {
1084                 schednetisr(NETISR_IP);
1085         }
1086 #else
1087         if(IF_QFULL(&ipintrq))
1088         {
1089                 NDBGL4(L4_IPRDBG, "ipr%d: ipintrq full!", unit);
1090                 IF_DROP(&ipintrq);
1091                 sc->sc_if.if_ierrors++;
1092                 sc->sc_if.if_iqdrops++;
1093                 m_freem(m);
1094         }
1095         else
1096         {
1097                 IF_ENQUEUE(&ipintrq, m);
1098                 schednetisr(NETISR_IP);
1099         }
1100 #endif  
1101 }
1102
1103 /*---------------------------------------------------------------------------*
1104  *      this routine is called from the HSCX interrupt handler
1105  *      when the last frame has been sent out and there is no
1106  *      further frame (mbuf) in the tx queue.
1107  *---------------------------------------------------------------------------*/
1108 static void
1109 ipr_tx_queue_empty(int unit)
1110 {
1111         register struct ipr_softc *sc = &ipr_softc[unit];
1112         register struct mbuf *m;
1113 #ifdef  IPR_VJ  
1114         struct ip *ip;  
1115 #endif
1116         int x = 0;
1117
1118         if(sc->sc_state != ST_CONNECTED_A)
1119                 return;
1120                 
1121         for(;;)
1122         {
1123                 IF_DEQUEUE(&sc->sc_fastq, m);
1124                 if(m)
1125                 {
1126                         sc->sc_if.if_omcasts++;
1127                 }
1128                 else
1129                 {
1130                         IF_DEQUEUE(&sc->sc_if.if_snd, m);
1131                         if(m == NULL)
1132                                 break;
1133                 }
1134
1135                 microtime(&sc->sc_if.if_lastchange);
1136                 
1137 #if NBPFILTER > 0 || NBPF > 0
1138                 if(sc->sc_if.if_bpf)
1139                 {
1140                         /* prepend the address family as a four byte field */
1141         
1142                         struct mbuf mm;
1143                         u_int af = AF_INET;
1144                         mm.m_next = m;
1145                         mm.m_len = 4;
1146                         mm.m_data = (char *)&af;
1147         
1148 #ifdef __FreeBSD__
1149                         bpf_mtap(&sc->sc_if, &mm);
1150 #else
1151                         bpf_mtap(sc->sc_if.if_bpf, &mm);
1152 #endif
1153                 }
1154 #endif /* NBPFILTER */
1155         
1156 #if I4BIPRACCT
1157                 sc->sc_outb += m->m_pkthdr.len; /* size before compression */
1158 #endif
1159
1160 #ifdef  IPR_VJ  
1161                 if((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP)
1162                 {
1163                         if(sc->sc_if.if_flags & IPR_COMPRESS)
1164                         {
1165                                 *mtod(m, u_char *) |= sl_compress_tcp(m, ip,
1166                                         &sc->sc_compr, 1);
1167                         }
1168                 }
1169 #endif
1170                 x = 1;
1171
1172                 IF_LOCK(isdn_linktab[unit]->tx_queue);
1173                 if(_IF_QFULL(isdn_linktab[unit]->tx_queue))
1174                 {
1175                         NDBGL4(L4_IPRDBG, "ipr%d: tx queue full!", unit);
1176                         m_freem(m);
1177                 }
1178                 else
1179                 {
1180                         sc->sc_if.if_obytes += m->m_pkthdr.len;
1181
1182                         sc->sc_if.if_opackets++;
1183
1184                         _IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
1185
1186                 }
1187                 IF_UNLOCK(isdn_linktab[unit]->tx_queue);
1188         }
1189
1190         if(x)
1191                 (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
1192 }
1193
1194 /*---------------------------------------------------------------------------*
1195  *      this routine is called from the HSCX interrupt handler
1196  *      each time a packet is received or transmitted. It should
1197  *      be used to implement an activity timeout mechanism.
1198  *---------------------------------------------------------------------------*/
1199 static void
1200 ipr_activity(int unit, int rxtx)
1201 {
1202         ipr_softc[unit].sc_cdp->last_active_time = SECOND;
1203 }
1204
1205 /*---------------------------------------------------------------------------*
1206  *      return this drivers linktab address
1207  *---------------------------------------------------------------------------*/
1208 drvr_link_t *
1209 ipr_ret_linktab(int unit)
1210 {
1211         return(&ipr_drvr_linktab[unit]);
1212 }
1213
1214 /*---------------------------------------------------------------------------*
1215  *      setup the isdn_linktab for this driver
1216  *---------------------------------------------------------------------------*/
1217 void
1218 ipr_set_linktab(int unit, isdn_link_t *ilt)
1219 {
1220         isdn_linktab[unit] = ilt;
1221 }
1222
1223 /*---------------------------------------------------------------------------*
1224  *      initialize this drivers linktab
1225  *---------------------------------------------------------------------------*/
1226 static void
1227 ipr_init_linktab(int unit)
1228 {
1229         ipr_drvr_linktab[unit].unit = unit;
1230         ipr_drvr_linktab[unit].bch_rx_data_ready = ipr_rx_data_rdy;
1231         ipr_drvr_linktab[unit].bch_tx_queue_empty = ipr_tx_queue_empty;
1232         ipr_drvr_linktab[unit].bch_activity = ipr_activity;
1233         ipr_drvr_linktab[unit].line_connected = ipr_connect;
1234         ipr_drvr_linktab[unit].line_disconnected = ipr_disconnect;
1235         ipr_drvr_linktab[unit].dial_response = ipr_dialresponse;
1236         ipr_drvr_linktab[unit].updown_ind = ipr_updown; 
1237 }
1238
1239 /*===========================================================================*/
1240
1241 #endif /* NI4BIPR > 0 */