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