Remove bogus checks after kmalloc(M_WAITOK) which never returns NULL.
[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.21 2008/01/06 16:55:52 swildner 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(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 /*---------------------------------------------------------------------------*
416  *      process ioctl
417  *---------------------------------------------------------------------------*/
418 static int
419 i4biprioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data, struct ucred *cr)
420 {
421         struct ipr_softc *sc = ifp->if_softc;
422
423         struct ifreq *ifr = (struct ifreq *)data;
424         struct ifaddr *ifa = (struct ifaddr *)data;
425         int error = 0;
426
427         crit_enter();
428         
429         switch (cmd)
430         {
431                 case SIOCAIFADDR:       /* add interface address */
432                 case SIOCSIFADDR:       /* set interface address */
433                 case SIOCSIFDSTADDR:    /* set interface destination address */
434                         if(ifa->ifa_addr->sa_family != AF_INET)
435                                 error = EAFNOSUPPORT;
436                         else
437                                 sc->sc_if.if_flags |= IFF_UP;
438                         microtime(&sc->sc_if.if_lastchange);
439                         break;
440
441                 case SIOCSIFFLAGS:      /* set interface flags */
442                         if(!(ifr->ifr_flags & IFF_UP))
443                         {
444                                 if(sc->sc_if.if_flags & IFF_RUNNING)
445                                 {
446                                         /* disconnect ISDN line */
447                                         i4b_l4_drvrdisc(BDRV_IPR, sc->sc_unit);
448                                         sc->sc_if.if_flags &= ~IFF_RUNNING;
449                                 }
450
451                                 sc->sc_state = ST_IDLE;
452
453                                 /* empty queues */
454
455                                 iprclearqueues(sc);
456                         }
457
458                         if(ifr->ifr_flags & IFF_DEBUG)
459                         {
460                                 /* enable debug messages */
461                         }
462                         
463                         microtime(&sc->sc_if.if_lastchange);
464                         break;
465
466                 case SIOCSIFMTU:        /* set interface MTU */
467                         if(ifr->ifr_mtu > I4BIPRMAXMTU)
468                                 error = EINVAL;
469                         else if(ifr->ifr_mtu < I4BIPRMINMTU)
470                                 error = EINVAL;
471                         else
472                         {
473                                 ifp->if_mtu = ifr->ifr_mtu;
474                                 microtime(&sc->sc_if.if_lastchange);
475                         }
476                         break;
477
478 #if 0
479         /* not needed for FreeBSD, done in sl_compress_init() (-hm) */
480         
481                         /* need to add an ioctl:        set VJ max slot ID
482                          * #define IPRIOCSMAXCID        _IOW('I', XXX, int)
483                          */
484 #ifdef IPR_VJ
485                 case IPRIOCSMAXCID:
486                         {
487                         struct thread *td = curthread;  /* XXX */
488
489                         if ((error = suser(td)) != 0)
490                                 return (error);
491                         sl_compress_setup(sc->sc_compr, *(int *)data);
492                         }
493                         break;
494 #endif
495 #endif
496                 default:
497                         error = EINVAL;
498                         break;
499         }
500
501         crit_exit();
502
503         return(error);
504 }
505
506 /*---------------------------------------------------------------------------*
507  *      clear the interface's send queues
508  *---------------------------------------------------------------------------*/
509 static void
510 iprclearqueues(struct ipr_softc *sc)
511 {
512         struct mbuf *m;
513
514         for(;;)
515         {
516                 crit_enter();
517                 IF_DEQUEUE(&sc->sc_fastq, m);
518                 crit_exit();
519                 if(m)
520                         m_freem(m);
521                 else
522                         break;
523         }
524
525         for(;;)
526         {
527                 crit_enter();
528                 IF_DEQUEUE(&sc->sc_if.if_snd, m);
529                 crit_exit();
530                 if(m)
531                         m_freem(m);
532                 else
533                         break;
534         }
535 }
536         
537 #if I4BIPRACCT
538 /*---------------------------------------------------------------------------*
539  *      watchdog routine
540  *---------------------------------------------------------------------------*/
541 static void
542 iprwatchdog(struct ifnet *ifp)
543 {
544         struct ipr_softc *sc = ifp->if_softc;
545         int unit = sc->sc_unit;
546         bchan_statistics_t bs;
547         
548         /* get # of bytes in and out from the HSCX driver */ 
549         
550         (*isdn_linktab[unit]->bch_stat)
551                 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
552
553         sc->sc_ioutb += bs.outbytes;
554         sc->sc_iinb += bs.inbytes;
555         
556         if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) 
557         {
558                 int ri = (sc->sc_iinb - sc->sc_linb)/I4BIPRACCTINTVL;
559                 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BIPRACCTINTVL;
560
561                 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
562                         sc->sc_fn = 0;
563                 else
564                         sc->sc_fn = 1;
565                         
566                 sc->sc_linb = sc->sc_iinb;
567                 sc->sc_loutb = sc->sc_ioutb;
568
569                 i4b_l4_accounting(BDRV_IPR, unit, ACCT_DURING,
570                          sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb);
571         }
572         sc->sc_if.if_timer = I4BIPRACCTINTVL;   
573 }
574 #endif /* I4BIPRACCT */
575
576 /*===========================================================================*
577  *                      ISDN INTERFACE ROUTINES
578  *===========================================================================*/
579
580 /*---------------------------------------------------------------------------*
581  *      start transmitting after connect
582  *---------------------------------------------------------------------------*/
583 static void
584 i4bipr_connect_startio(struct ipr_softc *sc)
585 {
586         crit_enter();
587         
588         if(sc->sc_state == ST_CONNECTED_W)
589         {
590                 sc->sc_state = ST_CONNECTED_A;
591                 ipr_tx_queue_empty(THE_UNIT);
592         }
593
594         crit_exit();
595 }
596  
597 /*---------------------------------------------------------------------------*
598  *      this routine is called from L4 handler at connect time
599  *---------------------------------------------------------------------------*/
600 static void
601 ipr_connect(int unit, void *cdp)
602 {
603         struct ipr_softc *sc = &ipr_softc[unit];
604
605         sc->sc_cdp = (call_desc_t *)cdp;
606
607         crit_enter();
608
609         NDBGL4(L4_DIALST, "ipr%d: setting dial state to ST_CONNECTED", unit);
610
611         sc->sc_if.if_flags |= IFF_RUNNING;
612         sc->sc_state = ST_CONNECTED_W;
613
614         sc->sc_dialresp = DSTAT_NONE;
615         sc->sc_lastdialresp = DSTAT_NONE;       
616         
617 #if I4BIPRACCT
618         sc->sc_iinb = 0;
619         sc->sc_ioutb = 0;
620         sc->sc_inb = 0;
621         sc->sc_outb = 0;
622         sc->sc_linb = 0;
623         sc->sc_loutb = 0;
624         sc->sc_if.if_timer = I4BIPRACCTINTVL;
625 #endif
626
627 #ifdef I4BIPRADJFRXP
628         sc->sc_first_pkt = 1;
629 #endif
630
631         /*
632          * Sometimes ISDN B-channels are switched thru asymmetic. This
633          * means that under such circumstances B-channel data (the first
634          * three packets of a TCP connection in my case) may get lost,
635          * causing a large delay until the connection is started.
636          * When the sending of the very first packet of a TCP connection
637          * is delayed for a to be empirically determined delay (close
638          * to a second in my case) those packets go thru and the TCP
639          * connection comes up "almost" immediately (-hm).
640          */
641
642         if(sc->sc_cdp->isdntxdelay > 0)
643         {
644                 int delay;
645
646                 if (hz == 100) {
647                         delay = sc->sc_cdp->isdntxdelay;        /* avoid any rounding */
648                 } else {
649                         delay = sc->sc_cdp->isdntxdelay*hz;
650                         delay /= 100;
651                 }
652
653                 callout_reset(&sc->sc_timeout, delay,
654                                 (TIMEOUT_FUNC_T)i4bipr_connect_startio, sc);
655         }
656         else
657         {
658                 sc->sc_state = ST_CONNECTED_A;
659                 ipr_tx_queue_empty(unit);
660         }
661
662         crit_exit();
663
664         /* we don't need any negotiation - pass event back right now */
665         i4b_l4_negcomplete(sc->sc_cdp);
666 }
667         
668 /*---------------------------------------------------------------------------*
669  *      this routine is called from L4 handler at disconnect time
670  *---------------------------------------------------------------------------*/
671 static void
672 ipr_disconnect(int unit, void *cdp)
673 {
674         call_desc_t *cd = (call_desc_t *)cdp;
675         struct ipr_softc *sc = &ipr_softc[unit];
676
677         /* new stuff to check that the active channel is being closed */
678
679         if (cd != sc->sc_cdp)
680         {
681                 NDBGL4(L4_IPRDBG, "ipr%d: channel %d not active",
682                                 cd->driver_unit, cd->channelid);
683                 return;
684         }
685
686 #if I4BIPRACCT
687         sc->sc_if.if_timer = 0;
688 #endif
689 #if IPR_LOG
690         /* show next IPR_LOG packets again */
691         sc->sc_log_first = IPR_LOG;
692 #endif
693
694         i4b_l4_accounting(BDRV_IPR, cd->driver_unit, ACCT_FINAL,
695                  sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb);
696         
697         sc->sc_cdp = (call_desc_t *)0;  
698
699         NDBGL4(L4_DIALST, "setting dial state to ST_IDLE");
700
701         sc->sc_dialresp = DSTAT_NONE;
702         sc->sc_lastdialresp = DSTAT_NONE;       
703
704         sc->sc_if.if_flags &= ~IFF_RUNNING;
705         sc->sc_state = ST_IDLE;
706 }
707
708 /*---------------------------------------------------------------------------*
709  *      this routine is used to give a feedback from userland daemon
710  *      in case of dial problems
711  *---------------------------------------------------------------------------*/
712 static void
713 ipr_dialresponse(int unit, int status, cause_t cause)
714 {
715         struct ipr_softc *sc = &ipr_softc[unit];
716         sc->sc_dialresp = status;
717
718         NDBGL4(L4_IPRDBG, "ipr%d: last=%d, this=%d",
719                 unit, sc->sc_lastdialresp, sc->sc_dialresp);
720
721         if(status != DSTAT_NONE)
722         {
723                 NDBGL4(L4_IPRDBG, "ipr%d: clearing queues", unit);
724                 iprclearqueues(sc);
725         }
726 }
727         
728 /*---------------------------------------------------------------------------*
729  *      interface soft up/down
730  *---------------------------------------------------------------------------*/
731 static void
732 ipr_updown(int unit, int updown)
733 {
734         struct ipr_softc *sc = &ipr_softc[unit];
735         sc->sc_updown = updown;
736 }
737         
738 /*---------------------------------------------------------------------------*
739  *      this routine is called from the HSCX interrupt handler
740  *      when a new frame (mbuf) has been received and was put on
741  *      the rx queue. It is assumed that this routines runs in
742  *      a critical section ! Keep it short !
743  *---------------------------------------------------------------------------*/
744 static void
745 ipr_rx_data_rdy(int unit)
746 {
747         struct ipr_softc *sc = &ipr_softc[unit];
748         struct mbuf *m;
749 #ifdef IPR_VJ
750 #ifdef IPR_VJ_USEBUFFER
751         u_char *cp = sc->sc_cbuf;
752 #endif  
753         int len, c;
754 #endif
755         static const uint32_t af = AF_INET;
756         
757         if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
758                 return;
759
760         m->m_pkthdr.rcvif = &sc->sc_if;
761
762         m->m_pkthdr.len = m->m_len;
763
764         microtime(&sc->sc_if.if_lastchange);
765
766 #ifdef I4BIPRADJFRXP
767
768         /*
769          * The very first packet after the B channel is switched thru
770          * has very often several bytes of random data prepended. This
771          * routine looks where the IP header starts and removes the
772          * the bad data.
773          */
774
775         if(sc->sc_first_pkt)
776         {
777                 unsigned char *mp = m->m_data;
778                 int i;
779                 
780                 sc->sc_first_pkt = 0;
781
782                 for(i = 0; i < m->m_len; i++, mp++)
783                 {
784                         if( ((*mp & 0xf0) == 0x40) &&
785                             ((*mp & 0x0f) >= 0x05) )
786                         {
787                                 m->m_data = mp;
788                                 m->m_pkthdr.len -= i;                           
789                                 break;
790                         }
791                 }
792         }
793 #endif
794                 
795         sc->sc_if.if_ipackets++;
796         sc->sc_if.if_ibytes += m->m_pkthdr.len;
797
798 #ifdef  IPR_VJ
799         if((c = (*(mtod(m, u_char *)) & 0xf0)) != (IPVERSION << 4))
800         {
801                 /* copy data to buffer */
802
803                 len = m->m_len;
804
805 #ifdef IPR_VJ_USEBUFFER
806 /* XXX */       m_copydata(m, 0, len, cp);
807 #endif
808                 
809                 if(c & 0x80)
810                 {
811                         c = TYPE_COMPRESSED_TCP;
812                 }
813                 else if(c == TYPE_UNCOMPRESSED_TCP)
814                 {
815 #ifdef IPR_VJ_USEBUFFER
816                         *cp &= 0x4f;            /* XXX */
817 #else
818                         *(mtod(m, u_char *)) &= 0x4f;                   
819 #endif                  
820                 }
821
822                 /*
823                  * We've got something that's not an IP packet.
824                  * If compression is enabled, try to decompress it.
825                  * Otherwise, if `auto-enable' compression is on and
826                  * it's a reasonable packet, decompress it and then
827                  * enable compression.  Otherwise, drop it.
828                  */
829                 if(sc->sc_if.if_flags & IPR_COMPRESS)
830                 {
831 #ifdef IPR_VJ_USEBUFFER
832                         len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
833 #else
834                         len = sl_uncompress_tcp((u_char **)&m->m_data, len,
835                                         (u_int)c, &sc->sc_compr);
836 #endif                  
837
838                         if(len <= 0)
839                         {
840 #ifdef DEBUG_IPR_VJ
841                                 kprintf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_COMPRESS!\n");
842 #endif
843                                 goto error;
844                         }
845                 }
846                 else if((sc->sc_if.if_flags & IPR_AUTOCOMP) &&
847                         (c == TYPE_UNCOMPRESSED_TCP) && (len >= 40))
848                 {
849 #ifdef IPR_VJ_USEBUFFER
850                         len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
851 #else
852                         len = sl_uncompress_tcp((u_char **)&m->m_data, len,
853                                         (u_int)c, &sc->sc_compr);
854 #endif
855
856                         if(len <= 0)
857                         {
858 #ifdef DEBUG_IPR_VJ
859                                 kprintf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_AUTOCOMP!\n");
860 #endif
861                                 goto error;
862                         }
863
864                         sc->sc_if.if_flags |= IPR_COMPRESS;
865                 }
866                 else
867                 {
868 #ifdef DEBUG_IPR_VJ
869                         kprintf("i4b_ipr, ipr_input: invalid ip packet!\n");
870 #endif
871
872 error:
873                         sc->sc_if.if_ierrors++;
874                         sc->sc_if.if_collisions++;
875                         m_freem(m);
876                         return;
877                 }
878 #ifdef IPR_VJ_USEBUFFER
879 /* XXX */       m_copyback(m, 0, len, cp);
880 #else
881                 m->m_len = m->m_pkthdr.len = len;
882 #endif
883         }
884 #endif
885
886 #if I4BIPRACCT
887         /* NB. do the accounting after decompression!           */
888         sc->sc_inb += m->m_pkthdr.len;
889 #endif
890 #if IPR_LOG
891         if(sc->sc_log_first > 0)
892         {
893                 --(sc->sc_log_first);
894                 i4b_l4_packet_ind(BDRV_IPR, unit, 0, m );
895         }
896 #endif
897
898         if (sc->sc_if.if_bpf)
899                 bpf_ptap(sc->sc_if.if_bpf, m, &af, sizeof(af));
900
901         if (netisr_queue(NETISR_IP, m)) {
902                 NDBGL4(L4_IPRDBG, "ipr%d: ipintrq full!", unit);
903                 sc->sc_if.if_ierrors++;
904                 sc->sc_if.if_iqdrops++;         
905         }
906 }
907
908 /*---------------------------------------------------------------------------*
909  *      this routine is called from the HSCX interrupt handler
910  *      when the last frame has been sent out and there is no
911  *      further frame (mbuf) in the tx queue.
912  *---------------------------------------------------------------------------*/
913 static void
914 ipr_tx_queue_empty(int unit)
915 {
916         static const uint32_t af = AF_INET;
917         struct ipr_softc *sc = &ipr_softc[unit];
918         struct mbuf *m;
919 #ifdef  IPR_VJ  
920         struct ip *ip;  
921 #endif
922         int x = 0;
923
924         if(sc->sc_state != ST_CONNECTED_A)
925                 return;
926                 
927         for(;;)
928         {
929                 IF_DEQUEUE(&sc->sc_fastq, m);
930                 if(m)
931                 {
932                         sc->sc_if.if_omcasts++;
933                 }
934                 else
935                 {
936                         IF_DEQUEUE(&sc->sc_if.if_snd, m);
937                         if(m == NULL)
938                                 break;
939                 }
940
941                 microtime(&sc->sc_if.if_lastchange);
942
943                 if (sc->sc_if.if_bpf)
944                         bpf_ptap(sc->sc_if.if_bpf, m, &af, sizeof(af));
945         
946 #if I4BIPRACCT
947                 sc->sc_outb += m->m_pkthdr.len; /* size before compression */
948 #endif
949
950 #ifdef  IPR_VJ  
951                 if((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP)
952                 {
953                         if(sc->sc_if.if_flags & IPR_COMPRESS)
954                         {
955                                 *mtod(m, u_char *) |= sl_compress_tcp(m, ip,
956                                         &sc->sc_compr, 1);
957                         }
958                 }
959 #endif
960                 x = 1;
961
962                 if(IF_QFULL(isdn_linktab[unit]->tx_queue))
963                 {
964                         NDBGL4(L4_IPRDBG, "ipr%d: tx queue full!", unit);
965                         m_freem(m);
966                 }
967                 else
968                 {
969                         sc->sc_if.if_obytes += m->m_pkthdr.len;
970
971                         sc->sc_if.if_opackets++;
972
973                         IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
974
975                 }
976         }
977
978         if(x)
979                 (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
980 }
981
982 /*---------------------------------------------------------------------------*
983  *      this routine is called from the HSCX interrupt handler
984  *      each time a packet is received or transmitted. It should
985  *      be used to implement an activity timeout mechanism.
986  *---------------------------------------------------------------------------*/
987 static void
988 ipr_activity(int unit, int rxtx)
989 {
990         ipr_softc[unit].sc_cdp->last_active_time = SECOND;
991 }
992
993 /*---------------------------------------------------------------------------*
994  *      return this drivers linktab address
995  *---------------------------------------------------------------------------*/
996 drvr_link_t *
997 ipr_ret_linktab(int unit)
998 {
999         return(&ipr_drvr_linktab[unit]);
1000 }
1001
1002 /*---------------------------------------------------------------------------*
1003  *      setup the isdn_linktab for this driver
1004  *---------------------------------------------------------------------------*/
1005 void
1006 ipr_set_linktab(int unit, isdn_link_t *ilt)
1007 {
1008         isdn_linktab[unit] = ilt;
1009 }
1010
1011 /*---------------------------------------------------------------------------*
1012  *      initialize this drivers linktab
1013  *---------------------------------------------------------------------------*/
1014 static void
1015 ipr_init_linktab(int unit)
1016 {
1017         ipr_drvr_linktab[unit].unit = unit;
1018         ipr_drvr_linktab[unit].bch_rx_data_ready = ipr_rx_data_rdy;
1019         ipr_drvr_linktab[unit].bch_tx_queue_empty = ipr_tx_queue_empty;
1020         ipr_drvr_linktab[unit].bch_activity = ipr_activity;
1021         ipr_drvr_linktab[unit].line_connected = ipr_connect;
1022         ipr_drvr_linktab[unit].line_disconnected = ipr_disconnect;
1023         ipr_drvr_linktab[unit].dial_response = ipr_dialresponse;
1024         ipr_drvr_linktab[unit].updown_ind = ipr_updown; 
1025 }
1026
1027 /*===========================================================================*/
1028
1029 #endif /* NI4BIPR > 0 */