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