bccffb2c8fdd457f448438cc89e785c508881fdc
[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.8 2003/09/15 23:38:13 hsu 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 "use_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 "use_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 <net/i4b/include/machine/i4b_debug.h>
131 #include <net/i4b/include/machine/i4b_ioctl.h>
132 #else
133 #include <i4b/i4b_debug.h>
134 #include <i4b/i4b_ioctl.h>
135 #endif
136
137 #include "../include/i4b_global.h"
138 #include "../include/i4b_l3l4.h"
139
140 #include "../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 (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__)
502         if (netisr_queue(NETISR_IP, m))
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 #endif
510         
511         NDBGL4(L4_IPRDBG, "ipr%d: add packet to send queue!", unit);
512         
513         ipr_tx_queue_empty(unit);
514
515         splx(s);
516
517         return (0);
518 }
519
520 /*---------------------------------------------------------------------------*
521  *      process ioctl
522  *---------------------------------------------------------------------------*/
523 #ifdef __FreeBSD__
524 static int
525 i4biprioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data)
526 #else
527 static int
528 i4biprioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
529 #endif
530 {
531 #if defined(__FreeBSD__) || defined(__bsdi__)
532         struct ipr_softc *sc = &ipr_softc[ifp->if_unit];
533 #else
534         struct ipr_softc *sc = ifp->if_softc;
535 #endif
536
537         struct ifreq *ifr = (struct ifreq *)data;
538         struct ifaddr *ifa = (struct ifaddr *)data;
539         int s;
540         int error = 0;
541
542         s = SPLI4B();
543         
544         switch (cmd)
545         {
546                 case SIOCAIFADDR:       /* add interface address */
547                 case SIOCSIFADDR:       /* set interface address */
548                 case SIOCSIFDSTADDR:    /* set interface destination address */
549                         if(ifa->ifa_addr->sa_family != AF_INET)
550                                 error = EAFNOSUPPORT;
551                         else
552                                 sc->sc_if.if_flags |= IFF_UP;
553                         microtime(&sc->sc_if.if_lastchange);
554                         break;
555
556                 case SIOCSIFFLAGS:      /* set interface flags */
557                         if(!(ifr->ifr_flags & IFF_UP))
558                         {
559                                 if(sc->sc_if.if_flags & IFF_RUNNING)
560                                 {
561                                         /* disconnect ISDN line */
562 #if defined(__FreeBSD__) || defined(__bsdi__)
563                                         i4b_l4_drvrdisc(BDRV_IPR, ifp->if_unit);
564 #else
565                                         i4b_l4_drvrdisc(BDRV_IPR, sc->sc_unit);
566 #endif
567                                         sc->sc_if.if_flags &= ~IFF_RUNNING;
568                                 }
569
570                                 sc->sc_state = ST_IDLE;
571
572                                 /* empty queues */
573
574                                 iprclearqueues(sc);
575                         }
576
577                         if(ifr->ifr_flags & IFF_DEBUG)
578                         {
579                                 /* enable debug messages */
580                         }
581                         
582                         microtime(&sc->sc_if.if_lastchange);
583                         break;
584
585 #if !defined(__OpenBSD__)                       
586                 case SIOCSIFMTU:        /* set interface MTU */
587                         if(ifr->ifr_mtu > I4BIPRMAXMTU)
588                                 error = EINVAL;
589                         else if(ifr->ifr_mtu < I4BIPRMINMTU)
590                                 error = EINVAL;
591                         else
592                         {
593                                 ifp->if_mtu = ifr->ifr_mtu;
594                                 microtime(&sc->sc_if.if_lastchange);
595                         }
596                         break;
597 #endif /* __OPENBSD__ */
598
599 #if 0
600         /* not needed for FreeBSD, done in sl_compress_init() (-hm) */
601         
602                         /* need to add an ioctl:        set VJ max slot ID
603                          * #define IPRIOCSMAXCID        _IOW('I', XXX, int)
604                          */
605 #ifdef IPR_VJ
606                 case IPRIOCSMAXCID:
607                         {
608                         struct thread *td = curthread;  /* XXX */
609
610                         if ((error = suser(td)) != 0)
611                                 return (error);
612                         sl_compress_setup(sc->sc_compr, *(int *)data);
613                         }
614                         break;
615 #endif
616 #endif
617                 default:
618                         error = EINVAL;
619                         break;
620         }
621
622         splx(s);
623
624         return(error);
625 }
626
627 /*---------------------------------------------------------------------------*
628  *      clear the interface's send queues
629  *---------------------------------------------------------------------------*/
630 static void
631 iprclearqueues(struct ipr_softc *sc)
632 {
633         int x;
634
635 #if defined (__FreeBSD__) && __FreeBSD__ > 4
636         x = splimp();
637         IF_DRAIN(&sc->sc_fastq);
638         IF_DRAIN(&sc->sc_if.if_snd);
639         splx(x);
640 #else
641         struct mbuf *m;
642
643         for(;;)
644         {
645                 x = splimp();
646                 IF_DEQUEUE(&sc->sc_fastq, m);
647                 splx(x);
648                 if(m)
649                         m_freem(m);
650                 else
651                         break;
652         }
653
654         for(;;)
655         {
656                 x = splimp();
657                 IF_DEQUEUE(&sc->sc_if.if_snd, m);
658                 splx(x);
659                 if(m)
660                         m_freem(m);
661                 else
662                         break;
663         }
664 #endif
665 }
666         
667 #if I4BIPRACCT
668 /*---------------------------------------------------------------------------*
669  *      watchdog routine
670  *---------------------------------------------------------------------------*/
671 #ifdef __bsdi__
672 static int
673 iprwatchdog(int unit)
674 {
675 #else
676 static void
677 iprwatchdog(struct ifnet *ifp)
678 {
679 #endif
680 #ifdef __FreeBSD__
681         int unit = ifp->if_unit;
682         struct ipr_softc *sc = &ipr_softc[unit];
683 #elif defined(__bsdi__)
684         struct ipr_softc *sc = &ipr_softc[unit];
685         struct ifnet *ifp = &ipr_softc[unit].sc_if;
686 #else
687         struct ipr_softc *sc = ifp->if_softc;
688         int unit = sc->sc_unit;
689 #endif
690         bchan_statistics_t bs;
691         
692         /* get # of bytes in and out from the HSCX driver */ 
693         
694         (*isdn_linktab[unit]->bch_stat)
695                 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
696
697         sc->sc_ioutb += bs.outbytes;
698         sc->sc_iinb += bs.inbytes;
699         
700         if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) 
701         {
702                 int ri = (sc->sc_iinb - sc->sc_linb)/I4BIPRACCTINTVL;
703                 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BIPRACCTINTVL;
704
705                 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
706                         sc->sc_fn = 0;
707                 else
708                         sc->sc_fn = 1;
709                         
710                 sc->sc_linb = sc->sc_iinb;
711                 sc->sc_loutb = sc->sc_ioutb;
712
713                 i4b_l4_accounting(BDRV_IPR, unit, ACCT_DURING,
714                          sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb);
715         }
716         sc->sc_if.if_timer = I4BIPRACCTINTVL;   
717 #ifdef __bsdi__
718         return 0;
719 #endif
720 }
721 #endif /* I4BIPRACCT */
722
723 /*===========================================================================*
724  *                      ISDN INTERFACE ROUTINES
725  *===========================================================================*/
726
727 /*---------------------------------------------------------------------------*
728  *      start transmitting after connect
729  *---------------------------------------------------------------------------*/
730 static void
731 i4bipr_connect_startio(struct ipr_softc *sc)
732 {
733         int s = SPLI4B();
734         
735         if(sc->sc_state == ST_CONNECTED_W)
736         {
737                 sc->sc_state = ST_CONNECTED_A;
738                 ipr_tx_queue_empty(THE_UNIT);
739         }
740
741         splx(s);
742 }
743  
744 /*---------------------------------------------------------------------------*
745  *      this routine is called from L4 handler at connect time
746  *---------------------------------------------------------------------------*/
747 static void
748 ipr_connect(int unit, void *cdp)
749 {
750         struct ipr_softc *sc = &ipr_softc[unit];
751         int s;
752
753         sc->sc_cdp = (call_desc_t *)cdp;
754
755         s = SPLI4B();
756
757         NDBGL4(L4_DIALST, "ipr%d: setting dial state to ST_CONNECTED", unit);
758
759         sc->sc_if.if_flags |= IFF_RUNNING;
760         sc->sc_state = ST_CONNECTED_W;
761
762         sc->sc_dialresp = DSTAT_NONE;
763         sc->sc_lastdialresp = DSTAT_NONE;       
764         
765 #if I4BIPRACCT
766         sc->sc_iinb = 0;
767         sc->sc_ioutb = 0;
768         sc->sc_inb = 0;
769         sc->sc_outb = 0;
770         sc->sc_linb = 0;
771         sc->sc_loutb = 0;
772         sc->sc_if.if_timer = I4BIPRACCTINTVL;
773 #endif
774
775 #ifdef I4BIPRADJFRXP
776         sc->sc_first_pkt = 1;
777 #endif
778
779         /*
780          * Sometimes ISDN B-channels are switched thru asymmetic. This
781          * means that under such circumstances B-channel data (the first
782          * three packets of a TCP connection in my case) may get lost,
783          * causing a large delay until the connection is started.
784          * When the sending of the very first packet of a TCP connection
785          * is delayed for a to be empirically determined delay (close
786          * to a second in my case) those packets go thru and the TCP
787          * connection comes up "almost" immediately (-hm).
788          */
789
790         if(sc->sc_cdp->isdntxdelay > 0)
791         {
792                 int delay;
793
794                 if (hz == 100) {
795                         delay = sc->sc_cdp->isdntxdelay;        /* avoid any rounding */
796                 } else {
797                         delay = sc->sc_cdp->isdntxdelay*hz;
798                         delay /= 100;
799                 }
800
801                 START_TIMER(sc->sc_callout, (TIMEOUT_FUNC_T)i4bipr_connect_startio, (void *)sc,  delay);
802         }
803         else
804         {
805                 sc->sc_state = ST_CONNECTED_A;
806                 ipr_tx_queue_empty(unit);
807         }
808
809         splx(s);
810
811         /* we don't need any negotiation - pass event back right now */
812         i4b_l4_negcomplete(sc->sc_cdp);
813 }
814         
815 /*---------------------------------------------------------------------------*
816  *      this routine is called from L4 handler at disconnect time
817  *---------------------------------------------------------------------------*/
818 static void
819 ipr_disconnect(int unit, void *cdp)
820 {
821         call_desc_t *cd = (call_desc_t *)cdp;
822         struct ipr_softc *sc = &ipr_softc[unit];
823
824         /* new stuff to check that the active channel is being closed */
825
826         if (cd != sc->sc_cdp)
827         {
828                 NDBGL4(L4_IPRDBG, "ipr%d: channel %d not active",
829                                 cd->driver_unit, cd->channelid);
830                 return;
831         }
832
833 #if I4BIPRACCT
834         sc->sc_if.if_timer = 0;
835 #endif
836 #if IPR_LOG
837         /* show next IPR_LOG packets again */
838         sc->sc_log_first = IPR_LOG;
839 #endif
840
841         i4b_l4_accounting(BDRV_IPR, cd->driver_unit, ACCT_FINAL,
842                  sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb);
843         
844         sc->sc_cdp = (call_desc_t *)0;  
845
846         NDBGL4(L4_DIALST, "setting dial state to ST_IDLE");
847
848         sc->sc_dialresp = DSTAT_NONE;
849         sc->sc_lastdialresp = DSTAT_NONE;       
850
851         sc->sc_if.if_flags &= ~IFF_RUNNING;
852         sc->sc_state = ST_IDLE;
853 }
854
855 /*---------------------------------------------------------------------------*
856  *      this routine is used to give a feedback from userland daemon
857  *      in case of dial problems
858  *---------------------------------------------------------------------------*/
859 static void
860 ipr_dialresponse(int unit, int status, cause_t cause)
861 {
862         struct ipr_softc *sc = &ipr_softc[unit];
863         sc->sc_dialresp = status;
864
865         NDBGL4(L4_IPRDBG, "ipr%d: last=%d, this=%d",
866                 unit, sc->sc_lastdialresp, sc->sc_dialresp);
867
868         if(status != DSTAT_NONE)
869         {
870                 NDBGL4(L4_IPRDBG, "ipr%d: clearing queues", unit);
871                 iprclearqueues(sc);
872         }
873 }
874         
875 /*---------------------------------------------------------------------------*
876  *      interface soft up/down
877  *---------------------------------------------------------------------------*/
878 static void
879 ipr_updown(int unit, int updown)
880 {
881         struct ipr_softc *sc = &ipr_softc[unit];
882         sc->sc_updown = updown;
883 }
884         
885 /*---------------------------------------------------------------------------*
886  *      this routine is called from the HSCX interrupt handler
887  *      when a new frame (mbuf) has been received and was put on
888  *      the rx queue. It is assumed that this routines runs at
889  *      pri level splimp() ! Keep it short !
890  *---------------------------------------------------------------------------*/
891 static void
892 ipr_rx_data_rdy(int unit)
893 {
894         struct ipr_softc *sc = &ipr_softc[unit];
895         struct mbuf *m;
896 #ifdef IPR_VJ
897 #ifdef IPR_VJ_USEBUFFER
898         u_char *cp = sc->sc_cbuf;
899 #endif  
900         int len, c;
901 #endif
902         
903         if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
904                 return;
905
906         m->m_pkthdr.rcvif = &sc->sc_if;
907
908         m->m_pkthdr.len = m->m_len;
909
910         microtime(&sc->sc_if.if_lastchange);
911
912 #ifdef I4BIPRADJFRXP
913
914         /*
915          * The very first packet after the B channel is switched thru
916          * has very often several bytes of random data prepended. This
917          * routine looks where the IP header starts and removes the
918          * the bad data.
919          */
920
921         if(sc->sc_first_pkt)
922         {
923                 unsigned char *mp = m->m_data;
924                 int i;
925                 
926                 sc->sc_first_pkt = 0;
927
928                 for(i = 0; i < m->m_len; i++, mp++)
929                 {
930                         if( ((*mp & 0xf0) == 0x40) &&
931                             ((*mp & 0x0f) >= 0x05) )
932                         {
933                                 m->m_data = mp;
934                                 m->m_pkthdr.len -= i;                           
935                                 break;
936                         }
937                 }
938         }
939 #endif
940                 
941         sc->sc_if.if_ipackets++;
942         sc->sc_if.if_ibytes += m->m_pkthdr.len;
943
944 #ifdef  IPR_VJ
945         if((c = (*(mtod(m, u_char *)) & 0xf0)) != (IPVERSION << 4))
946         {
947                 /* copy data to buffer */
948
949                 len = m->m_len;
950
951 #ifdef IPR_VJ_USEBUFFER
952 /* XXX */       m_copydata(m, 0, len, cp);
953 #endif
954                 
955                 if(c & 0x80)
956                 {
957                         c = TYPE_COMPRESSED_TCP;
958                 }
959                 else if(c == TYPE_UNCOMPRESSED_TCP)
960                 {
961 #ifdef IPR_VJ_USEBUFFER
962                         *cp &= 0x4f;            /* XXX */
963 #else
964                         *(mtod(m, u_char *)) &= 0x4f;                   
965 #endif                  
966                 }
967
968                 /*
969                  * We've got something that's not an IP packet.
970                  * If compression is enabled, try to decompress it.
971                  * Otherwise, if `auto-enable' compression is on and
972                  * it's a reasonable packet, decompress it and then
973                  * enable compression.  Otherwise, drop it.
974                  */
975                 if(sc->sc_if.if_flags & IPR_COMPRESS)
976                 {
977 #ifdef IPR_VJ_USEBUFFER
978                         len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
979 #else
980                         len = sl_uncompress_tcp((u_char **)&m->m_data, len,
981                                         (u_int)c, &sc->sc_compr);
982 #endif                  
983
984                         if(len <= 0)
985                         {
986 #ifdef DEBUG_IPR_VJ
987                                 printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_COMPRESS!\n");
988 #endif
989                                 goto error;
990                         }
991                 }
992                 else if((sc->sc_if.if_flags & IPR_AUTOCOMP) &&
993                         (c == TYPE_UNCOMPRESSED_TCP) && (len >= 40))
994                 {
995 #ifdef IPR_VJ_USEBUFFER
996                         len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
997 #else
998                         len = sl_uncompress_tcp((u_char **)&m->m_data, len,
999                                         (u_int)c, &sc->sc_compr);
1000 #endif
1001
1002                         if(len <= 0)
1003                         {
1004 #ifdef DEBUG_IPR_VJ
1005                                 printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_AUTOCOMP!\n");
1006 #endif
1007                                 goto error;
1008                         }
1009
1010                         sc->sc_if.if_flags |= IPR_COMPRESS;
1011                 }
1012                 else
1013                 {
1014 #ifdef DEBUG_IPR_VJ
1015                         printf("i4b_ipr, ipr_input: invalid ip packet!\n");
1016 #endif
1017
1018 error:
1019                         sc->sc_if.if_ierrors++;
1020                         sc->sc_if.if_collisions++;
1021                         m_freem(m);
1022                         return;
1023                 }
1024 #ifdef IPR_VJ_USEBUFFER
1025 /* XXX */       m_copyback(m, 0, len, cp);
1026 #else
1027                 m->m_len = m->m_pkthdr.len = len;
1028 #endif
1029         }
1030 #endif
1031
1032 #if I4BIPRACCT
1033         /* NB. do the accounting after decompression!           */
1034         sc->sc_inb += m->m_pkthdr.len;
1035 #endif
1036 #if IPR_LOG
1037         if(sc->sc_log_first > 0)
1038         {
1039                 --(sc->sc_log_first);
1040                 i4b_l4_packet_ind(BDRV_IPR, unit, 0, m );
1041         }
1042 #endif
1043
1044 #if NBPFILTER > 0 || NBPF > 0
1045         if(sc->sc_if.if_bpf)
1046         {
1047                 /* prepend the address family as a four byte field */           
1048                 struct mbuf mm;
1049                 u_int af = AF_INET;
1050                 mm.m_next = m;
1051                 mm.m_len = 4;
1052                 mm.m_data = (char *)&af;
1053
1054 #ifdef __FreeBSD__
1055                 bpf_mtap(&sc->sc_if, &mm);
1056 #else
1057                 bpf_mtap(sc->sc_if.if_bpf, &mm);
1058 #endif
1059         }
1060 #endif /* NBPFILTER > 0  || NBPF > 0 */
1061
1062 #if defined (__FreeBSD__)
1063         if (netisr_queue(NETISR_IP, m)) {
1064                 NDBGL4(L4_IPRDBG, "ipr%d: ipintrq full!", unit);
1065                 sc->sc_if.if_ierrors++;
1066                 sc->sc_if.if_iqdrops++;         
1067         }
1068 #endif
1069 }
1070
1071 /*---------------------------------------------------------------------------*
1072  *      this routine is called from the HSCX interrupt handler
1073  *      when the last frame has been sent out and there is no
1074  *      further frame (mbuf) in the tx queue.
1075  *---------------------------------------------------------------------------*/
1076 static void
1077 ipr_tx_queue_empty(int unit)
1078 {
1079         struct ipr_softc *sc = &ipr_softc[unit];
1080         struct mbuf *m;
1081 #ifdef  IPR_VJ  
1082         struct ip *ip;  
1083 #endif
1084         int x = 0;
1085
1086         if(sc->sc_state != ST_CONNECTED_A)
1087                 return;
1088                 
1089         for(;;)
1090         {
1091                 IF_DEQUEUE(&sc->sc_fastq, m);
1092                 if(m)
1093                 {
1094                         sc->sc_if.if_omcasts++;
1095                 }
1096                 else
1097                 {
1098                         IF_DEQUEUE(&sc->sc_if.if_snd, m);
1099                         if(m == NULL)
1100                                 break;
1101                 }
1102
1103                 microtime(&sc->sc_if.if_lastchange);
1104                 
1105 #if NBPFILTER > 0 || NBPF > 0
1106                 if(sc->sc_if.if_bpf)
1107                 {
1108                         /* prepend the address family as a four byte field */
1109         
1110                         struct mbuf mm;
1111                         u_int af = AF_INET;
1112                         mm.m_next = m;
1113                         mm.m_len = 4;
1114                         mm.m_data = (char *)&af;
1115         
1116 #ifdef __FreeBSD__
1117                         bpf_mtap(&sc->sc_if, &mm);
1118 #else
1119                         bpf_mtap(sc->sc_if.if_bpf, &mm);
1120 #endif
1121                 }
1122 #endif /* NBPFILTER */
1123         
1124 #if I4BIPRACCT
1125                 sc->sc_outb += m->m_pkthdr.len; /* size before compression */
1126 #endif
1127
1128 #ifdef  IPR_VJ  
1129                 if((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP)
1130                 {
1131                         if(sc->sc_if.if_flags & IPR_COMPRESS)
1132                         {
1133                                 *mtod(m, u_char *) |= sl_compress_tcp(m, ip,
1134                                         &sc->sc_compr, 1);
1135                         }
1136                 }
1137 #endif
1138                 x = 1;
1139
1140                 IF_LOCK(isdn_linktab[unit]->tx_queue);
1141                 if(_IF_QFULL(isdn_linktab[unit]->tx_queue))
1142                 {
1143                         NDBGL4(L4_IPRDBG, "ipr%d: tx queue full!", unit);
1144                         m_freem(m);
1145                 }
1146                 else
1147                 {
1148                         sc->sc_if.if_obytes += m->m_pkthdr.len;
1149
1150                         sc->sc_if.if_opackets++;
1151
1152                         _IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
1153
1154                 }
1155                 IF_UNLOCK(isdn_linktab[unit]->tx_queue);
1156         }
1157
1158         if(x)
1159                 (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
1160 }
1161
1162 /*---------------------------------------------------------------------------*
1163  *      this routine is called from the HSCX interrupt handler
1164  *      each time a packet is received or transmitted. It should
1165  *      be used to implement an activity timeout mechanism.
1166  *---------------------------------------------------------------------------*/
1167 static void
1168 ipr_activity(int unit, int rxtx)
1169 {
1170         ipr_softc[unit].sc_cdp->last_active_time = SECOND;
1171 }
1172
1173 /*---------------------------------------------------------------------------*
1174  *      return this drivers linktab address
1175  *---------------------------------------------------------------------------*/
1176 drvr_link_t *
1177 ipr_ret_linktab(int unit)
1178 {
1179         return(&ipr_drvr_linktab[unit]);
1180 }
1181
1182 /*---------------------------------------------------------------------------*
1183  *      setup the isdn_linktab for this driver
1184  *---------------------------------------------------------------------------*/
1185 void
1186 ipr_set_linktab(int unit, isdn_link_t *ilt)
1187 {
1188         isdn_linktab[unit] = ilt;
1189 }
1190
1191 /*---------------------------------------------------------------------------*
1192  *      initialize this drivers linktab
1193  *---------------------------------------------------------------------------*/
1194 static void
1195 ipr_init_linktab(int unit)
1196 {
1197         ipr_drvr_linktab[unit].unit = unit;
1198         ipr_drvr_linktab[unit].bch_rx_data_ready = ipr_rx_data_rdy;
1199         ipr_drvr_linktab[unit].bch_tx_queue_empty = ipr_tx_queue_empty;
1200         ipr_drvr_linktab[unit].bch_activity = ipr_activity;
1201         ipr_drvr_linktab[unit].line_connected = ipr_connect;
1202         ipr_drvr_linktab[unit].line_disconnected = ipr_disconnect;
1203         ipr_drvr_linktab[unit].dial_response = ipr_dialresponse;
1204         ipr_drvr_linktab[unit].updown_ind = ipr_updown; 
1205 }
1206
1207 /*===========================================================================*/
1208
1209 #endif /* NI4BIPR > 0 */