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