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