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