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