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