Merge from vendor branch BINUTILS:
[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.9 2004/01/06 03:17:26 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 "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 #if defined(__FreeBSD__) && !defined(__DragonFly__)
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 #if !defined(__FreeBSD__) || defined(__DragonFly__)
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(__DragonFly__)) || (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 __DragonFly__
292                 if_initname(&(sc->sc_if), "ipr", i);
293 #elif defined(__FreeBSD__)
294                 sc->sc_if.if_name = "ipr";
295                 sc->sc_if.if_unit = i;
296 #elif defined(__bsdi__)
297                 sc->sc_if.if_name = "ipr";
298                 sc->sc_if.if_unit = i;
299 #else
300                 sprintf(sc->sc_if.if_xname, "ipr%d", i);
301                 sc->sc_if.if_softc = sc;
302                 sc->sc_unit = i;
303 #endif
304
305 #ifdef  IPR_VJ
306                 sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_SIMPLEX | IPR_AUTOCOMP;
307 #else
308                 sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_SIMPLEX;
309 #endif
310
311 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
312                 callout_init(&sc->sc_callout);
313 #endif
314
315                 sc->sc_if.if_mtu = I4BIPRMTU;
316                 sc->sc_if.if_type = IFT_ISDNBASIC;
317                 sc->sc_if.if_ioctl = i4biprioctl;
318                 sc->sc_if.if_output = i4biproutput;
319
320                 sc->sc_if.if_snd.ifq_maxlen = I4BIPRMAXQLEN;
321                 sc->sc_fastq.ifq_maxlen = I4BIPRMAXQLEN;
322
323 #if defined (__FreeBSD__) && __FreeBSD__ > 4
324                 mtx_init(&sc->sc_fastq.ifq_mtx, "i4b_ipr_fastq", MTX_DEF);
325 #endif          
326                 sc->sc_if.if_ipackets = 0;
327                 sc->sc_if.if_ierrors = 0;
328                 sc->sc_if.if_opackets = 0;
329                 sc->sc_if.if_oerrors = 0;
330                 sc->sc_if.if_collisions = 0;
331                 sc->sc_if.if_ibytes = 0;
332                 sc->sc_if.if_obytes = 0;
333                 sc->sc_if.if_imcasts = 0;
334                 sc->sc_if.if_omcasts = 0;
335                 sc->sc_if.if_iqdrops = 0;
336                 sc->sc_if.if_noproto = 0;
337
338 #if I4BIPRACCT
339                 sc->sc_if.if_timer = 0; 
340                 sc->sc_if.if_watchdog = iprwatchdog;    
341                 sc->sc_iinb = 0;
342                 sc->sc_ioutb = 0;
343                 sc->sc_inb = 0;
344                 sc->sc_outb = 0;
345                 sc->sc_linb = 0;
346                 sc->sc_loutb = 0;
347                 sc->sc_fn = 1;
348 #endif
349 #if IPR_LOG
350                 sc->sc_log_first = IPR_LOG;
351 #endif
352
353 #ifdef  IPR_VJ
354 #ifdef __FreeBSD__
355                 sl_compress_init(&sc->sc_compr, -1);
356 #else
357                 sl_compress_init(&sc->sc_compr);
358 #endif
359
360 #ifdef IPR_VJ_USEBUFFER
361                 if(!((sc->sc_cbuf =
362                    (u_char *)malloc(I4BIPRMAXMTU+128, M_DEVBUF, M_WAITOK))))
363                 {
364                         panic("if_ipr.c, ipr_attach: VJ malloc failed");
365                 }
366 #endif
367 #endif
368                 sc->sc_updown = SOFT_ENA;       /* soft enabled */
369                 sc->sc_dialresp = DSTAT_NONE;   /* no response */
370                 sc->sc_lastdialresp = DSTAT_NONE;
371                 
372                 if_attach(&sc->sc_if);
373
374 #if NBPFILTER > 0 || NBPF > 0
375 #ifdef __FreeBSD__
376                 bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
377 #else
378                 bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_NULL, sizeof(u_int));
379 #endif
380 #endif          
381         }
382 }
383
384 /*---------------------------------------------------------------------------*
385  *      output a packet to the ISDN B-channel
386  *---------------------------------------------------------------------------*/
387 static int
388 i4biproutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
389          struct rtentry *rtp)
390 {
391         struct ipr_softc *sc;
392         int unit;
393         int s;
394         struct ifqueue *ifq;
395         struct ip *ip;
396         
397         s = SPLI4B();
398
399 #if (defined(__FreeBSD__) && !defined(__DragonFly__)) || (defined(__bsdi__))
400         unit = ifp->if_unit;
401         sc = &ipr_softc[unit];
402 #else
403         sc = ifp->if_softc;
404         unit = sc->sc_unit;
405 #endif
406
407         /* check for IP */
408         
409         if(dst->sa_family != AF_INET)
410         {
411                 printf(IPR_FMT "af%d not supported\n", IPR_ARG(sc), dst->sa_family);
412                 m_freem(m);
413                 splx(s);
414                 sc->sc_if.if_noproto++;
415                 sc->sc_if.if_oerrors++;
416                 return(EAFNOSUPPORT);
417         }
418
419         /* check interface state = UP */
420         
421         if(!(ifp->if_flags & IFF_UP))
422         {
423                 NDBGL4(L4_IPRDBG, "ipr%d: interface is DOWN!", unit);
424                 m_freem(m);
425                 splx(s);
426                 sc->sc_if.if_oerrors++;
427                 return(ENETDOWN);
428         }
429
430         /* dial if necessary */
431         
432         if(sc->sc_state == ST_IDLE || sc->sc_state == ST_DIALING)
433         {
434
435 #ifdef NOTDEF
436                 switch(sc->sc_dialresp)
437                 {
438                         case DSTAT_TFAIL:       /* transient failure */
439                                 NDBGL4(L4_IPRDBG, "ipr%d: transient dial failure!", unit);
440                                 m_freem(m);
441                                 iprclearqueues(sc);
442                                 sc->sc_dialresp = DSTAT_NONE;
443                                 splx(s);
444                                 sc->sc_if.if_oerrors++;
445                                 return(ENETUNREACH);
446                                 break;
447
448                         case DSTAT_PFAIL:       /* permanent failure */
449                                 NDBGL4(L4_IPRDBG, "ipr%d: permanent dial failure!", unit);
450                                 m_freem(m);
451                                 iprclearqueues(sc);
452                                 sc->sc_dialresp = DSTAT_NONE;
453                                 splx(s);
454                                 sc->sc_if.if_oerrors++;
455                                 return(EHOSTUNREACH);                           
456                                 break;
457
458                         case DSTAT_INONLY:      /* no dialout allowed*/
459                                 NDBGL4(L4_IPRDBG, "ipr%d: dialout not allowed failure!", unit);
460                                 m_freem(m);
461                                 iprclearqueues(sc);
462                                 sc->sc_dialresp = DSTAT_NONE;
463                                 splx(s);
464                                 sc->sc_if.if_oerrors++;
465                                 return(EHOSTUNREACH);                           
466                                 break;
467                 }
468 #endif
469
470                 NDBGL4(L4_IPRDBG, "ipr%d: send dial request message!", unit);
471                 NDBGL4(L4_DIALST, "ipr%d: setting dial state to ST_DIALING", unit);
472                 i4b_l4_dialout(BDRV_IPR, unit);
473                 sc->sc_state = ST_DIALING;
474         }
475
476 #if IPR_LOG
477         if(sc->sc_log_first > 0)
478         {
479                 --(sc->sc_log_first);
480                 i4b_l4_packet_ind(BDRV_IPR, unit, 1, m );
481         }
482 #endif
483
484         /* update access time */
485         
486         microtime(&sc->sc_if.if_lastchange);
487
488         /*
489          * check, if type of service indicates interactive, i.e. telnet,
490          * traffic. in case it is interactive, put it into the fast queue,
491          * else (i.e. ftp traffic) put it into the "normal" queue
492          */
493
494         ip = mtod(m, struct ip *);              /* get ptr to ip header */
495          
496         if(ip->ip_tos & IPTOS_LOWDELAY)
497                 ifq = &sc->sc_fastq;
498         else
499                 ifq = &sc->sc_if.if_snd;
500
501         /* check for space in choosen send queue */
502         
503 #if defined (__FreeBSD__)
504         if (netisr_queue(NETISR_IP, m))
505         {
506                 NDBGL4(L4_IPRDBG, "ipr%d: send queue full!", unit);
507                 splx(s);
508                 sc->sc_if.if_oerrors++;
509                 return(ENOBUFS);
510         }
511 #endif
512         
513         NDBGL4(L4_IPRDBG, "ipr%d: add packet to send queue!", unit);
514         
515         ipr_tx_queue_empty(unit);
516
517         splx(s);
518
519         return (0);
520 }
521
522 /*---------------------------------------------------------------------------*
523  *      process ioctl
524  *---------------------------------------------------------------------------*/
525 #ifdef __FreeBSD__
526 static int
527 i4biprioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data)
528 #else
529 static int
530 i4biprioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
531 #endif
532 {
533 #if (defined(__FreeBSD__) && !defined(__DragonFly__)) || (defined(__bsdi__))
534         struct ipr_softc *sc = &ipr_softc[ifp->if_unit];
535 #else
536         struct ipr_softc *sc = ifp->if_softc;
537 #endif
538
539         struct ifreq *ifr = (struct ifreq *)data;
540         struct ifaddr *ifa = (struct ifaddr *)data;
541         int s;
542         int error = 0;
543
544         s = SPLI4B();
545         
546         switch (cmd)
547         {
548                 case SIOCAIFADDR:       /* add interface address */
549                 case SIOCSIFADDR:       /* set interface address */
550                 case SIOCSIFDSTADDR:    /* set interface destination address */
551                         if(ifa->ifa_addr->sa_family != AF_INET)
552                                 error = EAFNOSUPPORT;
553                         else
554                                 sc->sc_if.if_flags |= IFF_UP;
555                         microtime(&sc->sc_if.if_lastchange);
556                         break;
557
558                 case SIOCSIFFLAGS:      /* set interface flags */
559                         if(!(ifr->ifr_flags & IFF_UP))
560                         {
561                                 if(sc->sc_if.if_flags & IFF_RUNNING)
562                                 {
563                                         /* disconnect ISDN line */
564 #if (defined(__FreeBSD__) && !defined(__DragonFly__)) || (defined(__bsdi__))
565                                         i4b_l4_drvrdisc(BDRV_IPR, ifp->if_unit);
566 #else
567                                         i4b_l4_drvrdisc(BDRV_IPR, sc->sc_unit);
568 #endif
569                                         sc->sc_if.if_flags &= ~IFF_RUNNING;
570                                 }
571
572                                 sc->sc_state = ST_IDLE;
573
574                                 /* empty queues */
575
576                                 iprclearqueues(sc);
577                         }
578
579                         if(ifr->ifr_flags & IFF_DEBUG)
580                         {
581                                 /* enable debug messages */
582                         }
583                         
584                         microtime(&sc->sc_if.if_lastchange);
585                         break;
586
587 #if !defined(__OpenBSD__)                       
588                 case SIOCSIFMTU:        /* set interface MTU */
589                         if(ifr->ifr_mtu > I4BIPRMAXMTU)
590                                 error = EINVAL;
591                         else if(ifr->ifr_mtu < I4BIPRMINMTU)
592                                 error = EINVAL;
593                         else
594                         {
595                                 ifp->if_mtu = ifr->ifr_mtu;
596                                 microtime(&sc->sc_if.if_lastchange);
597                         }
598                         break;
599 #endif /* __OPENBSD__ */
600
601 #if 0
602         /* not needed for FreeBSD, done in sl_compress_init() (-hm) */
603         
604                         /* need to add an ioctl:        set VJ max slot ID
605                          * #define IPRIOCSMAXCID        _IOW('I', XXX, int)
606                          */
607 #ifdef IPR_VJ
608                 case IPRIOCSMAXCID:
609                         {
610                         struct thread *td = curthread;  /* XXX */
611
612                         if ((error = suser(td)) != 0)
613                                 return (error);
614                         sl_compress_setup(sc->sc_compr, *(int *)data);
615                         }
616                         break;
617 #endif
618 #endif
619                 default:
620                         error = EINVAL;
621                         break;
622         }
623
624         splx(s);
625
626         return(error);
627 }
628
629 /*---------------------------------------------------------------------------*
630  *      clear the interface's send queues
631  *---------------------------------------------------------------------------*/
632 static void
633 iprclearqueues(struct ipr_softc *sc)
634 {
635         int x;
636
637 #if defined (__FreeBSD__) && __FreeBSD__ > 4
638         x = splimp();
639         IF_DRAIN(&sc->sc_fastq);
640         IF_DRAIN(&sc->sc_if.if_snd);
641         splx(x);
642 #else
643         struct mbuf *m;
644
645         for(;;)
646         {
647                 x = splimp();
648                 IF_DEQUEUE(&sc->sc_fastq, m);
649                 splx(x);
650                 if(m)
651                         m_freem(m);
652                 else
653                         break;
654         }
655
656         for(;;)
657         {
658                 x = splimp();
659                 IF_DEQUEUE(&sc->sc_if.if_snd, m);
660                 splx(x);
661                 if(m)
662                         m_freem(m);
663                 else
664                         break;
665         }
666 #endif
667 }
668         
669 #if I4BIPRACCT
670 /*---------------------------------------------------------------------------*
671  *      watchdog routine
672  *---------------------------------------------------------------------------*/
673 #ifdef __bsdi__
674 static int
675 iprwatchdog(int unit)
676 {
677 #else
678 static void
679 iprwatchdog(struct ifnet *ifp)
680 {
681 #endif
682 #if defined(__FreeBSD__) && !defined(__DragonFly__)
683         int unit = ifp->if_unit;
684         struct ipr_softc *sc = &ipr_softc[unit];
685 #elif defined(__bsdi__)
686         struct ipr_softc *sc = &ipr_softc[unit];
687         struct ifnet *ifp = &ipr_softc[unit].sc_if;
688 #else
689         struct ipr_softc *sc = ifp->if_softc;
690         int unit = sc->sc_unit;
691 #endif
692         bchan_statistics_t bs;
693         
694         /* get # of bytes in and out from the HSCX driver */ 
695         
696         (*isdn_linktab[unit]->bch_stat)
697                 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
698
699         sc->sc_ioutb += bs.outbytes;
700         sc->sc_iinb += bs.inbytes;
701         
702         if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) 
703         {
704                 int ri = (sc->sc_iinb - sc->sc_linb)/I4BIPRACCTINTVL;
705                 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BIPRACCTINTVL;
706
707                 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
708                         sc->sc_fn = 0;
709                 else
710                         sc->sc_fn = 1;
711                         
712                 sc->sc_linb = sc->sc_iinb;
713                 sc->sc_loutb = sc->sc_ioutb;
714
715                 i4b_l4_accounting(BDRV_IPR, unit, ACCT_DURING,
716                          sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb);
717         }
718         sc->sc_if.if_timer = I4BIPRACCTINTVL;   
719 #ifdef __bsdi__
720         return 0;
721 #endif
722 }
723 #endif /* I4BIPRACCT */
724
725 /*===========================================================================*
726  *                      ISDN INTERFACE ROUTINES
727  *===========================================================================*/
728
729 /*---------------------------------------------------------------------------*
730  *      start transmitting after connect
731  *---------------------------------------------------------------------------*/
732 static void
733 i4bipr_connect_startio(struct ipr_softc *sc)
734 {
735         int s = SPLI4B();
736         
737         if(sc->sc_state == ST_CONNECTED_W)
738         {
739                 sc->sc_state = ST_CONNECTED_A;
740                 ipr_tx_queue_empty(THE_UNIT);
741         }
742
743         splx(s);
744 }
745  
746 /*---------------------------------------------------------------------------*
747  *      this routine is called from L4 handler at connect time
748  *---------------------------------------------------------------------------*/
749 static void
750 ipr_connect(int unit, void *cdp)
751 {
752         struct ipr_softc *sc = &ipr_softc[unit];
753         int s;
754
755         sc->sc_cdp = (call_desc_t *)cdp;
756
757         s = SPLI4B();
758
759         NDBGL4(L4_DIALST, "ipr%d: setting dial state to ST_CONNECTED", unit);
760
761         sc->sc_if.if_flags |= IFF_RUNNING;
762         sc->sc_state = ST_CONNECTED_W;
763
764         sc->sc_dialresp = DSTAT_NONE;
765         sc->sc_lastdialresp = DSTAT_NONE;       
766         
767 #if I4BIPRACCT
768         sc->sc_iinb = 0;
769         sc->sc_ioutb = 0;
770         sc->sc_inb = 0;
771         sc->sc_outb = 0;
772         sc->sc_linb = 0;
773         sc->sc_loutb = 0;
774         sc->sc_if.if_timer = I4BIPRACCTINTVL;
775 #endif
776
777 #ifdef I4BIPRADJFRXP
778         sc->sc_first_pkt = 1;
779 #endif
780
781         /*
782          * Sometimes ISDN B-channels are switched thru asymmetic. This
783          * means that under such circumstances B-channel data (the first
784          * three packets of a TCP connection in my case) may get lost,
785          * causing a large delay until the connection is started.
786          * When the sending of the very first packet of a TCP connection
787          * is delayed for a to be empirically determined delay (close
788          * to a second in my case) those packets go thru and the TCP
789          * connection comes up "almost" immediately (-hm).
790          */
791
792         if(sc->sc_cdp->isdntxdelay > 0)
793         {
794                 int delay;
795
796                 if (hz == 100) {
797                         delay = sc->sc_cdp->isdntxdelay;        /* avoid any rounding */
798                 } else {
799                         delay = sc->sc_cdp->isdntxdelay*hz;
800                         delay /= 100;
801                 }
802
803                 START_TIMER(sc->sc_callout, (TIMEOUT_FUNC_T)i4bipr_connect_startio, (void *)sc,  delay);
804         }
805         else
806         {
807                 sc->sc_state = ST_CONNECTED_A;
808                 ipr_tx_queue_empty(unit);
809         }
810
811         splx(s);
812
813         /* we don't need any negotiation - pass event back right now */
814         i4b_l4_negcomplete(sc->sc_cdp);
815 }
816         
817 /*---------------------------------------------------------------------------*
818  *      this routine is called from L4 handler at disconnect time
819  *---------------------------------------------------------------------------*/
820 static void
821 ipr_disconnect(int unit, void *cdp)
822 {
823         call_desc_t *cd = (call_desc_t *)cdp;
824         struct ipr_softc *sc = &ipr_softc[unit];
825
826         /* new stuff to check that the active channel is being closed */
827
828         if (cd != sc->sc_cdp)
829         {
830                 NDBGL4(L4_IPRDBG, "ipr%d: channel %d not active",
831                                 cd->driver_unit, cd->channelid);
832                 return;
833         }
834
835 #if I4BIPRACCT
836         sc->sc_if.if_timer = 0;
837 #endif
838 #if IPR_LOG
839         /* show next IPR_LOG packets again */
840         sc->sc_log_first = IPR_LOG;
841 #endif
842
843         i4b_l4_accounting(BDRV_IPR, cd->driver_unit, ACCT_FINAL,
844                  sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb);
845         
846         sc->sc_cdp = (call_desc_t *)0;  
847
848         NDBGL4(L4_DIALST, "setting dial state to ST_IDLE");
849
850         sc->sc_dialresp = DSTAT_NONE;
851         sc->sc_lastdialresp = DSTAT_NONE;       
852
853         sc->sc_if.if_flags &= ~IFF_RUNNING;
854         sc->sc_state = ST_IDLE;
855 }
856
857 /*---------------------------------------------------------------------------*
858  *      this routine is used to give a feedback from userland daemon
859  *      in case of dial problems
860  *---------------------------------------------------------------------------*/
861 static void
862 ipr_dialresponse(int unit, int status, cause_t cause)
863 {
864         struct ipr_softc *sc = &ipr_softc[unit];
865         sc->sc_dialresp = status;
866
867         NDBGL4(L4_IPRDBG, "ipr%d: last=%d, this=%d",
868                 unit, sc->sc_lastdialresp, sc->sc_dialresp);
869
870         if(status != DSTAT_NONE)
871         {
872                 NDBGL4(L4_IPRDBG, "ipr%d: clearing queues", unit);
873                 iprclearqueues(sc);
874         }
875 }
876         
877 /*---------------------------------------------------------------------------*
878  *      interface soft up/down
879  *---------------------------------------------------------------------------*/
880 static void
881 ipr_updown(int unit, int updown)
882 {
883         struct ipr_softc *sc = &ipr_softc[unit];
884         sc->sc_updown = updown;
885 }
886         
887 /*---------------------------------------------------------------------------*
888  *      this routine is called from the HSCX interrupt handler
889  *      when a new frame (mbuf) has been received and was put on
890  *      the rx queue. It is assumed that this routines runs at
891  *      pri level splimp() ! Keep it short !
892  *---------------------------------------------------------------------------*/
893 static void
894 ipr_rx_data_rdy(int unit)
895 {
896         struct ipr_softc *sc = &ipr_softc[unit];
897         struct mbuf *m;
898 #ifdef IPR_VJ
899 #ifdef IPR_VJ_USEBUFFER
900         u_char *cp = sc->sc_cbuf;
901 #endif  
902         int len, c;
903 #endif
904         
905         if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
906                 return;
907
908         m->m_pkthdr.rcvif = &sc->sc_if;
909
910         m->m_pkthdr.len = m->m_len;
911
912         microtime(&sc->sc_if.if_lastchange);
913
914 #ifdef I4BIPRADJFRXP
915
916         /*
917          * The very first packet after the B channel is switched thru
918          * has very often several bytes of random data prepended. This
919          * routine looks where the IP header starts and removes the
920          * the bad data.
921          */
922
923         if(sc->sc_first_pkt)
924         {
925                 unsigned char *mp = m->m_data;
926                 int i;
927                 
928                 sc->sc_first_pkt = 0;
929
930                 for(i = 0; i < m->m_len; i++, mp++)
931                 {
932                         if( ((*mp & 0xf0) == 0x40) &&
933                             ((*mp & 0x0f) >= 0x05) )
934                         {
935                                 m->m_data = mp;
936                                 m->m_pkthdr.len -= i;                           
937                                 break;
938                         }
939                 }
940         }
941 #endif
942                 
943         sc->sc_if.if_ipackets++;
944         sc->sc_if.if_ibytes += m->m_pkthdr.len;
945
946 #ifdef  IPR_VJ
947         if((c = (*(mtod(m, u_char *)) & 0xf0)) != (IPVERSION << 4))
948         {
949                 /* copy data to buffer */
950
951                 len = m->m_len;
952
953 #ifdef IPR_VJ_USEBUFFER
954 /* XXX */       m_copydata(m, 0, len, cp);
955 #endif
956                 
957                 if(c & 0x80)
958                 {
959                         c = TYPE_COMPRESSED_TCP;
960                 }
961                 else if(c == TYPE_UNCOMPRESSED_TCP)
962                 {
963 #ifdef IPR_VJ_USEBUFFER
964                         *cp &= 0x4f;            /* XXX */
965 #else
966                         *(mtod(m, u_char *)) &= 0x4f;                   
967 #endif                  
968                 }
969
970                 /*
971                  * We've got something that's not an IP packet.
972                  * If compression is enabled, try to decompress it.
973                  * Otherwise, if `auto-enable' compression is on and
974                  * it's a reasonable packet, decompress it and then
975                  * enable compression.  Otherwise, drop it.
976                  */
977                 if(sc->sc_if.if_flags & IPR_COMPRESS)
978                 {
979 #ifdef IPR_VJ_USEBUFFER
980                         len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
981 #else
982                         len = sl_uncompress_tcp((u_char **)&m->m_data, len,
983                                         (u_int)c, &sc->sc_compr);
984 #endif                  
985
986                         if(len <= 0)
987                         {
988 #ifdef DEBUG_IPR_VJ
989                                 printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_COMPRESS!\n");
990 #endif
991                                 goto error;
992                         }
993                 }
994                 else if((sc->sc_if.if_flags & IPR_AUTOCOMP) &&
995                         (c == TYPE_UNCOMPRESSED_TCP) && (len >= 40))
996                 {
997 #ifdef IPR_VJ_USEBUFFER
998                         len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
999 #else
1000                         len = sl_uncompress_tcp((u_char **)&m->m_data, len,
1001                                         (u_int)c, &sc->sc_compr);
1002 #endif
1003
1004                         if(len <= 0)
1005                         {
1006 #ifdef DEBUG_IPR_VJ
1007                                 printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_AUTOCOMP!\n");
1008 #endif
1009                                 goto error;
1010                         }
1011
1012                         sc->sc_if.if_flags |= IPR_COMPRESS;
1013                 }
1014                 else
1015                 {
1016 #ifdef DEBUG_IPR_VJ
1017                         printf("i4b_ipr, ipr_input: invalid ip packet!\n");
1018 #endif
1019
1020 error:
1021                         sc->sc_if.if_ierrors++;
1022                         sc->sc_if.if_collisions++;
1023                         m_freem(m);
1024                         return;
1025                 }
1026 #ifdef IPR_VJ_USEBUFFER
1027 /* XXX */       m_copyback(m, 0, len, cp);
1028 #else
1029                 m->m_len = m->m_pkthdr.len = len;
1030 #endif
1031         }
1032 #endif
1033
1034 #if I4BIPRACCT
1035         /* NB. do the accounting after decompression!           */
1036         sc->sc_inb += m->m_pkthdr.len;
1037 #endif
1038 #if IPR_LOG
1039         if(sc->sc_log_first > 0)
1040         {
1041                 --(sc->sc_log_first);
1042                 i4b_l4_packet_ind(BDRV_IPR, unit, 0, m );
1043         }
1044 #endif
1045
1046 #if NBPFILTER > 0 || NBPF > 0
1047         if(sc->sc_if.if_bpf)
1048         {
1049                 /* prepend the address family as a four byte field */           
1050                 struct mbuf mm;
1051                 u_int af = AF_INET;
1052                 mm.m_next = m;
1053                 mm.m_len = 4;
1054                 mm.m_data = (char *)&af;
1055
1056 #ifdef __FreeBSD__
1057                 bpf_mtap(&sc->sc_if, &mm);
1058 #else
1059                 bpf_mtap(sc->sc_if.if_bpf, &mm);
1060 #endif
1061         }
1062 #endif /* NBPFILTER > 0  || NBPF > 0 */
1063
1064 #if defined (__FreeBSD__)
1065         if (netisr_queue(NETISR_IP, m)) {
1066                 NDBGL4(L4_IPRDBG, "ipr%d: ipintrq full!", unit);
1067                 sc->sc_if.if_ierrors++;
1068                 sc->sc_if.if_iqdrops++;         
1069         }
1070 #endif
1071 }
1072
1073 /*---------------------------------------------------------------------------*
1074  *      this routine is called from the HSCX interrupt handler
1075  *      when the last frame has been sent out and there is no
1076  *      further frame (mbuf) in the tx queue.
1077  *---------------------------------------------------------------------------*/
1078 static void
1079 ipr_tx_queue_empty(int unit)
1080 {
1081         struct ipr_softc *sc = &ipr_softc[unit];
1082         struct mbuf *m;
1083 #ifdef  IPR_VJ  
1084         struct ip *ip;  
1085 #endif
1086         int x = 0;
1087
1088         if(sc->sc_state != ST_CONNECTED_A)
1089                 return;
1090                 
1091         for(;;)
1092         {
1093                 IF_DEQUEUE(&sc->sc_fastq, m);
1094                 if(m)
1095                 {
1096                         sc->sc_if.if_omcasts++;
1097                 }
1098                 else
1099                 {
1100                         IF_DEQUEUE(&sc->sc_if.if_snd, m);
1101                         if(m == NULL)
1102                                 break;
1103                 }
1104
1105                 microtime(&sc->sc_if.if_lastchange);
1106                 
1107 #if NBPFILTER > 0 || NBPF > 0
1108                 if(sc->sc_if.if_bpf)
1109                 {
1110                         /* prepend the address family as a four byte field */
1111         
1112                         struct mbuf mm;
1113                         u_int af = AF_INET;
1114                         mm.m_next = m;
1115                         mm.m_len = 4;
1116                         mm.m_data = (char *)&af;
1117         
1118 #ifdef __FreeBSD__
1119                         bpf_mtap(&sc->sc_if, &mm);
1120 #else
1121                         bpf_mtap(sc->sc_if.if_bpf, &mm);
1122 #endif
1123                 }
1124 #endif /* NBPFILTER */
1125         
1126 #if I4BIPRACCT
1127                 sc->sc_outb += m->m_pkthdr.len; /* size before compression */
1128 #endif
1129
1130 #ifdef  IPR_VJ  
1131                 if((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP)
1132                 {
1133                         if(sc->sc_if.if_flags & IPR_COMPRESS)
1134                         {
1135                                 *mtod(m, u_char *) |= sl_compress_tcp(m, ip,
1136                                         &sc->sc_compr, 1);
1137                         }
1138                 }
1139 #endif
1140                 x = 1;
1141
1142                 IF_LOCK(isdn_linktab[unit]->tx_queue);
1143                 if(_IF_QFULL(isdn_linktab[unit]->tx_queue))
1144                 {
1145                         NDBGL4(L4_IPRDBG, "ipr%d: tx queue full!", unit);
1146                         m_freem(m);
1147                 }
1148                 else
1149                 {
1150                         sc->sc_if.if_obytes += m->m_pkthdr.len;
1151
1152                         sc->sc_if.if_opackets++;
1153
1154                         _IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
1155
1156                 }
1157                 IF_UNLOCK(isdn_linktab[unit]->tx_queue);
1158         }
1159
1160         if(x)
1161                 (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
1162 }
1163
1164 /*---------------------------------------------------------------------------*
1165  *      this routine is called from the HSCX interrupt handler
1166  *      each time a packet is received or transmitted. It should
1167  *      be used to implement an activity timeout mechanism.
1168  *---------------------------------------------------------------------------*/
1169 static void
1170 ipr_activity(int unit, int rxtx)
1171 {
1172         ipr_softc[unit].sc_cdp->last_active_time = SECOND;
1173 }
1174
1175 /*---------------------------------------------------------------------------*
1176  *      return this drivers linktab address
1177  *---------------------------------------------------------------------------*/
1178 drvr_link_t *
1179 ipr_ret_linktab(int unit)
1180 {
1181         return(&ipr_drvr_linktab[unit]);
1182 }
1183
1184 /*---------------------------------------------------------------------------*
1185  *      setup the isdn_linktab for this driver
1186  *---------------------------------------------------------------------------*/
1187 void
1188 ipr_set_linktab(int unit, isdn_link_t *ilt)
1189 {
1190         isdn_linktab[unit] = ilt;
1191 }
1192
1193 /*---------------------------------------------------------------------------*
1194  *      initialize this drivers linktab
1195  *---------------------------------------------------------------------------*/
1196 static void
1197 ipr_init_linktab(int unit)
1198 {
1199         ipr_drvr_linktab[unit].unit = unit;
1200         ipr_drvr_linktab[unit].bch_rx_data_ready = ipr_rx_data_rdy;
1201         ipr_drvr_linktab[unit].bch_tx_queue_empty = ipr_tx_queue_empty;
1202         ipr_drvr_linktab[unit].bch_activity = ipr_activity;
1203         ipr_drvr_linktab[unit].line_connected = ipr_connect;
1204         ipr_drvr_linktab[unit].line_disconnected = ipr_disconnect;
1205         ipr_drvr_linktab[unit].dial_response = ipr_dialresponse;
1206         ipr_drvr_linktab[unit].updown_ind = ipr_updown; 
1207 }
1208
1209 /*===========================================================================*/
1210
1211 #endif /* NI4BIPR > 0 */