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