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