summaryrefslogtreecommitdiffstats
path: root/sys/i4b/driver
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1998-12-27 21:47:14 +0000
committerphk <phk@FreeBSD.org>1998-12-27 21:47:14 +0000
commitc7ecc129d72ba32b5d83c9a6019e93fd181d719c (patch)
tree8d5099bc7ef24151b4f6deb00d1d34a7e7ac694a /sys/i4b/driver
parent3f431df8ec46b86090ad59ee153872c45d4d429d (diff)
downloadFreeBSD-src-c7ecc129d72ba32b5d83c9a6019e93fd181d719c.zip
FreeBSD-src-c7ecc129d72ba32b5d83c9a6019e93fd181d719c.tar.gz
Initial entry of ISDN4BSD into the FreeBSD tree.
ISDN4BSD is the work of our brand-new comitter: Hellmuth Michaelis, who has done a tremendous amount of work to bring us this far. There are still some outstanding issues and files to bring into the tree, and for now it will be needed to pick up all the extra docs from the isdn4bsd release. It is probably also a very good idea to subscribe to the isdn@freebsd.org mailing list before you try this out. These files correspond to release "beta Version 0.70.00 / December 1998" from Hellmuth.
Diffstat (limited to 'sys/i4b/driver')
-rw-r--r--sys/i4b/driver/i4b_ctl.c303
-rw-r--r--sys/i4b/driver/i4b_ipr.c1115
-rw-r--r--sys/i4b/driver/i4b_isppp.c710
-rw-r--r--sys/i4b/driver/i4b_rbch.c820
-rw-r--r--sys/i4b/driver/i4b_tel.c713
-rw-r--r--sys/i4b/driver/i4b_trace.c508
6 files changed, 4169 insertions, 0 deletions
diff --git a/sys/i4b/driver/i4b_ctl.c b/sys/i4b/driver/i4b_ctl.c
new file mode 100644
index 0000000..56bcb02
--- /dev/null
+++ b/sys/i4b/driver/i4b_ctl.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_ctl.c - i4b system control port driver
+ * ------------------------------------------
+ *
+ * $Id: i4b_ctl.c,v 1.17 1998/12/05 18:02:39 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 17:59:15 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "i4bctl.h"
+
+#if NI4BCTL > 1
+#error "only 1 (one) i4bctl device allowed!"
+#endif
+
+#if NI4BCTL > 0
+
+#include <sys/param.h>
+
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <sys/ioccom.h>
+#include <i386/isa/isa_device.h>
+#else
+#include <sys/ioctl.h>
+#endif
+
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#ifdef __FreeBSD__
+#include "opt_devfs.h"
+#endif
+
+#ifdef DEVFS
+#include <sys/devfsext.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#else
+#include <machine/bus.h>
+#include <sys/device.h>
+#include <i4b/i4b_debug.h>
+#include <i4b/i4b_ioctl.h>
+#endif
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/layer1/i4b_l1.h>
+
+static int openflag = 0;
+
+#if BSD > 199306 && defined(__FreeBSD__)
+static d_open_t i4bctlopen;
+static d_close_t i4bctlclose;
+static d_ioctl_t i4bctlioctl;
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+static d_poll_t i4bctlpoll;
+#endif
+
+#define CDEV_MAJOR 55
+static struct cdevsw i4bctl_cdevsw =
+ { i4bctlopen, i4bctlclose, noread, nowrite,
+ i4bctlioctl, nostop, nullreset, nodevtotty,
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ i4bctlpoll, nommap, NULL, "i4bctl", NULL, -1 };
+#else
+ noselect, nommap, NULL, "i4bctl", NULL, -1 };
+#endif
+
+static void i4bctlattach(void *);
+PSEUDO_SET(i4bctlattach, i4b_i4bctldrv);
+
+#define PDEVSTATIC static
+#endif /* __FreeBSD__ */
+
+#ifdef DEVFS
+static void *devfs_token;
+#endif
+
+#ifndef __FreeBSD__
+#define PDEVSTATIC /* */
+void i4bctlattach __P((void));
+int i4bctlopen __P((dev_t dev, int flag, int fmt, struct proc *p));
+int i4bctlclose __P((dev_t dev, int flag, int fmt, struct proc *p));
+int i4bctlioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+#endif /* !FreeBSD */
+
+#if BSD > 199306 && defined(__FreeBSD__)
+/*---------------------------------------------------------------------------*
+ * initialization at kernel load time
+ *---------------------------------------------------------------------------*/
+static void
+i4bctlinit(void *unused)
+{
+ dev_t dev;
+
+ dev = makedev(CDEV_MAJOR, 0);
+
+ cdevsw_add(&dev, &i4bctl_cdevsw, NULL);
+}
+
+SYSINIT(i4bctldev, SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, &i4bctlinit, NULL);
+
+#endif /* BSD > 199306 && defined(__FreeBSD__) */
+
+/*---------------------------------------------------------------------------*
+ * interface attach routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC void
+#ifdef __FreeBSD__
+i4bctlattach(void *dummy)
+#else
+i4bctlattach()
+#endif
+{
+#ifndef HACK_NO_PSEUDO_ATTACH_MSG
+ printf("i4bctl: ISDN system control port attached\n");
+#endif
+#ifdef DEVFS
+ devfs_token = devfs_add_devswf(&i4bctl_cdevsw, 0, DV_CHR,
+ UID_ROOT, GID_WHEEL, 0600,
+ "i4bctl", 0);
+#endif
+}
+
+/*---------------------------------------------------------------------------*
+ * i4bctlopen - device driver open routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4bctlopen(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ if(minor(dev))
+ return (ENXIO);
+
+ if(openflag)
+ return (EBUSY);
+
+ openflag = 1;
+
+ return (0);
+}
+
+/*---------------------------------------------------------------------------*
+ * i4bctlclose - device driver close routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4bctlclose(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ openflag = 0;
+ return (0);
+}
+
+/*---------------------------------------------------------------------------*
+ * i4bctlioctl - device driver ioctl routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+#if defined (__FreeBSD_version) && __FreeBSD_version >= 300003
+i4bctlioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+#else
+i4bctlioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+#endif
+{
+ ctl_debug_t *cdbg;
+ int error = 0;
+
+#ifndef DO_I4B_DEBUG
+ return(ENODEV);
+#else
+ if(minor(dev))
+ return(ENODEV);
+
+ switch(cmd)
+ {
+ case I4B_CTL_GET_DEBUG:
+ cdbg = (ctl_debug_t *)data;
+ cdbg->l1 = i4b_l1_debug;
+ cdbg->l2 = i4b_l2_debug;
+ cdbg->l3 = i4b_l3_debug;
+ cdbg->l4 = i4b_l4_debug;
+ break;
+
+ case I4B_CTL_SET_DEBUG:
+ cdbg = (ctl_debug_t *)data;
+ i4b_l1_debug = cdbg->l1;
+ i4b_l2_debug = cdbg->l2;
+ i4b_l3_debug = cdbg->l3;
+ i4b_l4_debug = cdbg->l4;
+ break;
+
+ case I4B_CTL_GET_HSCXSTAT:
+ {
+ hscxstat_t *hst;
+ struct isic_softc *sc;
+ hst = (hscxstat_t *)data;
+
+ if( hst->unit < 0 ||
+ hst->unit > ISIC_MAXUNIT ||
+ hst->chan < 0 ||
+ hst->chan > 1 )
+ {
+ error = EINVAL;
+ break;
+ }
+
+#ifndef __FreeBSD__
+ sc = isic_find_sc(hst->unit);
+#else
+ sc = &isic_sc[hst->unit];
+#endif
+ hst->vfr = sc->sc_chan[hst->chan].stat_VFR;
+ hst->rdo = sc->sc_chan[hst->chan].stat_RDO;
+ hst->crc = sc->sc_chan[hst->chan].stat_CRC;
+ hst->rab = sc->sc_chan[hst->chan].stat_RAB;
+ hst->xdu = sc->sc_chan[hst->chan].stat_XDU;
+ hst->rfo = sc->sc_chan[hst->chan].stat_RFO;
+ break;
+ }
+
+ case I4B_CTL_CLR_HSCXSTAT:
+ {
+ hscxstat_t *hst;
+ struct isic_softc *sc;
+ hst = (hscxstat_t *)data;
+
+ if( hst->unit < 0 ||
+ hst->unit > ISIC_MAXUNIT ||
+ hst->chan < 0 ||
+ hst->chan > 1 )
+ {
+ error = EINVAL;
+ break;
+ }
+
+#ifndef __FreeBSD__
+ sc = isic_find_sc(hst->unit);
+#else
+ sc = &isic_sc[hst->unit];
+#endif
+
+ sc->sc_chan[hst->chan].stat_VFR = 0;
+ sc->sc_chan[hst->chan].stat_RDO = 0;
+ sc->sc_chan[hst->chan].stat_CRC = 0;
+ sc->sc_chan[hst->chan].stat_RAB = 0;
+ sc->sc_chan[hst->chan].stat_XDU = 0;
+ sc->sc_chan[hst->chan].stat_RFO = 0;
+
+ break;
+ }
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return(error);
+#endif DO_I4B_DEBUG
+}
+
+/*---------------------------------------------------------------------------*
+ * i4bctlpoll - device driver poll routine
+ *---------------------------------------------------------------------------*/
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+static int
+i4bctlpoll (dev_t dev, int events, struct proc *p)
+{
+ return (ENODEV);
+}
+#endif
+
+#endif /* NI4BCTL > 0 */
diff --git a/sys/i4b/driver/i4b_ipr.c b/sys/i4b/driver/i4b_ipr.c
new file mode 100644
index 0000000..df3977c
--- /dev/null
+++ b/sys/i4b/driver/i4b_ipr.c
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_ipr.c - isdn4bsd IP over raw HDLC ISDN network driver
+ * ---------------------------------------------------------
+ *
+ * $Id: i4b_ipr.c,v 1.42 1998/12/18 14:20:44 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 11:50:47 1998]
+ *
+ *---------------------------------------------------------------------------*
+ *
+ * statistics counter usage (interface lifetime):
+ * ----------------------------------------------
+ * sc->sc_if.if_ipackets # of received packets
+ * sc->sc_if.if_ierrors # of error packets not going to upper layers
+ * sc->sc_if.if_opackets # of transmitted packets
+ * sc->sc_if.if_oerrors # of error packets not being transmitted
+ * sc->sc_if.if_collisions # of invalid ip packets after VJ decompression
+ * sc->sc_if.if_ibytes # of bytes coming in from the line (before VJ)
+ * sc->sc_if.if_obytes # of bytes going out to the line (after VJ)
+ * sc->sc_if.if_imcasts (currently unused)
+ * sc->sc_if.if_omcasts # of frames sent out of the fastqueue
+ * sc->sc_if.if_iqdrops # of frames dropped on input because queue full
+ * sc->sc_if.if_noproto # of frames dropped on output because !AF_INET
+ *
+ * statistics counter usage (connection lifetime):
+ * -----------------------------------------------
+ * sc->sc_iinb # of ISDN incoming bytes from HSCX
+ * sc->sc_ioutb # of ISDN outgoing bytes from HSCX
+ * sc->sc_inb # of incoming bytes after decompression
+ * sc->sc_outb # of outgoing bytes before compression
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "i4bipr.h"
+
+#if NI4BIPR > 0
+
+#ifdef __FreeBSD__
+#include "opt_i4b.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <sys/ioccom.h>
+#include <sys/sockio.h>
+#ifdef IPR_VJ
+#include <sys/malloc.h>
+#endif
+#else
+#include <sys/ioctl.h>
+#endif
+#include <sys/kernel.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+
+#ifdef IPR_VJ
+#include <net/slcompress.h>
+#define IPR_COMPRESS IFF_LINK0 /* compress TCP traffic */
+#define IPR_AUTOCOMP IFF_LINK1 /* auto-enable TCP compression */
+
+/*---------------------------------------------------------------------------
+ * NOTICE: using NO separate buffer relies on the assumption, that the HSCX
+ * IRQ handler _always_ allocates a single, continuous mbuf cluster large
+ * enough to hold the maximum MTU size if the ipr interface !
+ *
+ * CAUTION: i have re-defined IPR_VJ_USEBUFFER because it makes problems
+ * with 2 i4b's back to back running cvs over ssh, cvs simply
+ * aborts because it gets bad data. Everything else (telnet/ftp?etc)
+ * functions fine.
+ *---------------------------------------------------------------------------*/
+#define IPR_VJ_USEBUFFER /* define to use an allocated separate buffer*/
+ /* undef to uncompress in the mbuf itself */
+#endif /* IPR_VJ */
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <sys/time.h>
+#include <net/bpf.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_debug.h>
+#else
+#include <i4b/i4b_debug.h>
+#include <i4b/i4b_ioctl.h>
+#endif
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_l3l4.h>
+
+#include <i4b/layer4/i4b_l4.h>
+
+#ifndef __FreeBSD__
+#include <machine/cpu.h> /* For softnet */
+#endif
+
+#ifdef __FreeBSD__
+#define IPR_FMT "ipr%d: "
+#define IPR_ARG(sc) ((sc)->sc_if.if_unit)
+#define PDEVSTATIC static
+#else
+#define IPR_FMT "%s: "
+#define IPR_ARG(sc) ((sc)->sc_if.if_xname)
+#define PDEVSTATIC /* not static */
+#endif
+
+#define I4BIPRMTU 1500 /* regular MTU */
+#define I4BIPRMAXMTU 2000 /* max MTU */
+#define I4BIPRMINMTU 500 /* min MTU */
+
+#define I4BIPRMAXQLEN 50 /* max queue length */
+
+#define I4BIPRACCT 1 /* enable accounting messages */
+#define I4BIPRACCTINTVL 2 /* accounting msg interval in secs */
+#define I4BIPRADJFRXP 1 /* adjust 1st rxd packet */
+
+/* initialized by L4 */
+
+static drvr_link_t ipr_drvr_linktab[NI4BIPR];
+static isdn_link_t *isdn_linktab[NI4BIPR];
+
+struct ipr_softc {
+ struct ifnet sc_if; /* network-visible interface */
+ int sc_state; /* state of the interface */
+
+#ifndef __FreeBSD__
+ int sc_unit; /* unit number for Net/OpenBSD */
+#endif
+
+ call_desc_t *sc_cdp; /* ptr to call descriptor */
+ int sc_updown; /* soft state of interface */
+ struct ifqueue sc_fastq; /* interactive traffic */
+ int sc_dialresp; /* dialresponse */
+ int sc_lastdialresp;/* last dialresponse */
+
+#if I4BIPRACCT
+ int sc_iinb; /* isdn driver # of inbytes */
+ int sc_ioutb; /* isdn driver # of outbytes */
+ int sc_inb; /* # of bytes rx'd */
+ int sc_outb; /* # of bytes tx'd */
+ int sc_linb; /* last # of bytes rx'd */
+ int sc_loutb; /* last # of bytes tx'd */
+ int sc_fn; /* flag, first null acct */
+#endif
+
+#ifdef I4BIPRADJFRXP
+ int sc_first_pkt; /* flag, first rxd packet */
+#endif
+
+#ifdef IPR_VJ
+ struct slcompress sc_compr; /* tcp compression data */
+#ifdef IPR_VJ_USEBUFFER
+ u_char *sc_cbuf; /* tcp decompression buffer */
+#endif
+#endif
+
+} ipr_softc[NI4BIPR];
+
+enum ipr_states {
+ ST_IDLE, /* initialized, ready, idle */
+ ST_DIALING, /* dialling out to remote */
+ ST_CONNECTED_W, /* connected to remote */
+ ST_CONNECTED_A, /* connected to remote */
+};
+
+#ifdef __FreeBSD__
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+# define IOCTL_CMD_T u_long
+#else
+# define IOCTL_CMD_T int
+#endif
+PDEVSTATIC void i4biprattach(void *);
+PSEUDO_SET(i4biprattach, i4b_ipr);
+static int i4biprioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data);
+#else
+PDEVSTATIC void i4biprattach __P((void));
+static int i4biprioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
+#endif
+
+static void iprwatchdog(struct ifnet *ifp);
+static void ipr_init_linktab(int unit);
+static void ipr_tx_queue_empty(int unit);
+static int i4biproutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rtp);
+static void iprclearqueues(struct ipr_softc *sc);
+
+/*===========================================================================*
+ * DEVICE DRIVER ROUTINES
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * interface attach routine at kernel boot time
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC void
+#ifdef __FreeBSD__
+i4biprattach(void *dummy)
+#else
+i4biprattach()
+#endif
+{
+ struct ipr_softc *sc = ipr_softc;
+ int i;
+
+#ifndef HACK_NO_PSEUDO_ATTACH_MSG
+#ifdef IPR_VJ
+ printf("i4bipr: %d IP over raw HDLC ISDN device(s) attached (VJ header compression)\n", NI4BIPR);
+#else
+ printf("i4bipr: %d IP over raw HDLC ISDN device(s) attached\n", NI4BIPR);
+#endif
+#endif
+
+ for(i=0; i < NI4BIPR; sc++, i++)
+ {
+ ipr_init_linktab(i);
+
+ DBGL4(L4_DIALST, "i4biprattach", ("setting dial state to ST_IDLE\n"));
+
+ sc->sc_state = ST_IDLE;
+
+#ifdef __FreeBSD__
+ sc->sc_if.if_name = "ipr";
+#if __FreeBSD__ < 3
+ sc->sc_if.if_next = NULL;
+#endif
+ sc->sc_if.if_unit = i;
+#else
+ sprintf(sc->sc_if.if_xname, "ipr%d", i);
+ sc->sc_if.if_softc = sc;
+ sc->sc_unit = i;
+#endif
+
+#ifdef IPR_VJ
+ sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_SIMPLEX | IPR_AUTOCOMP;
+#else
+ sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_SIMPLEX;
+#endif
+
+ sc->sc_if.if_mtu = I4BIPRMTU;
+ sc->sc_if.if_type = IFT_ISDNBASIC;
+ sc->sc_if.if_ioctl = i4biprioctl;
+ sc->sc_if.if_output = i4biproutput;
+
+ sc->sc_if.if_snd.ifq_maxlen = I4BIPRMAXQLEN;
+ sc->sc_fastq.ifq_maxlen = I4BIPRMAXQLEN;
+
+ sc->sc_if.if_ipackets = 0;
+ sc->sc_if.if_ierrors = 0;
+ sc->sc_if.if_opackets = 0;
+ sc->sc_if.if_oerrors = 0;
+ sc->sc_if.if_collisions = 0;
+ sc->sc_if.if_ibytes = 0;
+ sc->sc_if.if_obytes = 0;
+ sc->sc_if.if_imcasts = 0;
+ sc->sc_if.if_omcasts = 0;
+ sc->sc_if.if_iqdrops = 0;
+ sc->sc_if.if_noproto = 0;
+
+#if I4BIPRACCT
+ sc->sc_if.if_timer = 0;
+ sc->sc_if.if_watchdog = iprwatchdog;
+ sc->sc_iinb = 0;
+ sc->sc_ioutb = 0;
+ sc->sc_inb = 0;
+ sc->sc_outb = 0;
+ sc->sc_linb = 0;
+ sc->sc_loutb = 0;
+ sc->sc_fn = 1;
+#endif
+
+#ifdef IPR_VJ
+#ifdef __FreeBSD__
+ sl_compress_init(&sc->sc_compr, -1);
+#else
+ sl_compress_init(&sc->sc_compr);
+#endif
+
+#ifdef IPR_VJ_USEBUFFER
+ if(!((sc->sc_cbuf =
+ (u_char *)malloc(I4BIPRMAXMTU+128, M_DEVBUF, M_WAITOK))))
+ {
+ panic("if_ipr.c, ipr_attach: VJ malloc failed");
+ }
+#endif
+#endif
+
+ sc->sc_updown = SOFT_ENA; /* soft enabled */
+
+ sc->sc_dialresp = DSTAT_NONE; /* no response */
+ sc->sc_lastdialresp = DSTAT_NONE;
+
+ if_attach(&sc->sc_if);
+
+#if NBPFILTER > 0
+#ifdef __FreeBSD__
+ bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
+#else
+ bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_NULL, sizeof(u_int));
+#endif
+#endif
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * output a packet to the ISDN B-channel
+ *---------------------------------------------------------------------------*/
+static int
+i4biproutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+ struct rtentry *rtp)
+{
+ struct ipr_softc *sc;
+ int unit;
+ int s;
+ struct ifqueue *ifq;
+ struct ip *ip;
+
+ s = SPLI4B();
+
+#ifdef __FreeBSD__
+ unit = ifp->if_unit;
+ sc = &ipr_softc[unit];
+#else
+ sc = ifp->if_softc;
+ unit = sc->sc_unit;
+#endif
+
+ /* check for IP */
+
+ if(dst->sa_family != AF_INET)
+ {
+ printf(IPR_FMT "af%d not supported\n", IPR_ARG(sc), dst->sa_family);
+ m_freem(m);
+ splx(s);
+ sc->sc_if.if_noproto++;
+ sc->sc_if.if_oerrors++;
+ return(EAFNOSUPPORT);
+ }
+
+ /* check interface state = UP */
+
+ if(!(ifp->if_flags & IFF_UP))
+ {
+ DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: interface is DOWN!\n", unit));
+ m_freem(m);
+ splx(s);
+ sc->sc_if.if_oerrors++;
+ return(ENETDOWN);
+ }
+
+ /* dial if necessary */
+
+ if(sc->sc_state == ST_IDLE || sc->sc_state == ST_DIALING)
+ {
+
+#ifdef NOTDEF
+ switch(sc->sc_dialresp)
+ {
+ case DSTAT_TFAIL: /* transient failure */
+ DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: transient dial failure!\n", unit));
+ m_freem(m);
+ iprclearqueues(sc);
+ sc->sc_dialresp = DSTAT_NONE;
+ splx(s);
+ sc->sc_if.if_oerrors++;
+ return(ENETUNREACH);
+ break;
+
+ case DSTAT_PFAIL: /* permanent failure */
+ DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: permanent dial failure!\n", unit));
+ m_freem(m);
+ iprclearqueues(sc);
+ sc->sc_dialresp = DSTAT_NONE;
+ splx(s);
+ sc->sc_if.if_oerrors++;
+ return(EHOSTUNREACH);
+ break;
+
+ case DSTAT_INONLY: /* no dialout allowed*/
+ DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: dialout not allowed failure!\n", unit));
+ m_freem(m);
+ iprclearqueues(sc);
+ sc->sc_dialresp = DSTAT_NONE;
+ splx(s);
+ sc->sc_if.if_oerrors++;
+ return(EHOSTUNREACH);
+ break;
+ }
+#endif
+
+ DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: send dial request message!\n", unit));
+ DBGL4(L4_DIALST, "i4biproutput", ("ipr%d: setting dial state to ST_DIALING\n", unit));
+ i4b_l4_dialout(BDRV_IPR, unit);
+ sc->sc_state = ST_DIALING;
+ }
+
+ /* update access time */
+
+ microtime(&sc->sc_if.if_lastchange);
+
+ /*
+ * check, if type of service indicates interactive, i.e. telnet,
+ * traffic. in case it is interactive, put it into the fast queue,
+ * else (i.e. ftp traffic) put it into the "normal" queue
+ */
+
+ ip = mtod(m, struct ip *); /* get ptr to ip header */
+
+ if(ip->ip_tos & IPTOS_LOWDELAY)
+ ifq = &sc->sc_fastq;
+ else
+ ifq = &sc->sc_if.if_snd;
+
+ /* check for space in choosen send queue */
+
+ if(IF_QFULL(ifq))
+ {
+ DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: send queue full!\n", unit));
+ IF_DROP(ifq);
+ m_freem(m);
+ splx(s);
+ sc->sc_if.if_oerrors++;
+ return(ENOBUFS);
+ }
+
+ DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: add packet to send queue!\n", unit));
+
+ IF_ENQUEUE(ifq, m);
+
+ ipr_tx_queue_empty(unit);
+
+ splx(s);
+
+ return (0);
+}
+
+/*---------------------------------------------------------------------------*
+ * process ioctl
+ *---------------------------------------------------------------------------*/
+#ifdef __FreeBSD__
+static int
+i4biprioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data)
+#else
+static int
+i4biprioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+#endif
+{
+#ifdef __FreeBSD__
+ struct ipr_softc *sc = &ipr_softc[ifp->if_unit];
+#else
+ struct ipr_softc *sc = ifp->if_softc;
+#endif
+
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ int s;
+ int error = 0;
+
+ s = SPLI4B();
+
+ switch (cmd)
+ {
+ case SIOCAIFADDR: /* add interface address */
+ case SIOCSIFADDR: /* set interface address */
+ case SIOCSIFDSTADDR: /* set interface destination address */
+ if(ifa->ifa_addr->sa_family != AF_INET)
+ error = EAFNOSUPPORT;
+ else
+ sc->sc_if.if_flags |= IFF_UP;
+ microtime(&sc->sc_if.if_lastchange);
+ break;
+
+ case SIOCSIFFLAGS: /* set interface flags */
+ if(!(ifr->ifr_flags & IFF_UP))
+ {
+ if(sc->sc_if.if_flags & IFF_RUNNING)
+ {
+ /* disconnect ISDN line */
+#ifdef __FreeBSD__
+ i4b_l4_drvrdisc(BDRV_IPR, ifp->if_unit);
+#else
+ i4b_l4_drvrdisc(BDRV_IPR, sc->sc_unit);
+#endif
+ sc->sc_if.if_flags &= ~IFF_RUNNING;
+ }
+
+ sc->sc_state = ST_IDLE;
+
+ /* empty queues */
+
+ iprclearqueues(sc);
+ }
+
+ if(ifr->ifr_flags & IFF_DEBUG)
+ {
+ /* enable debug messages */
+ }
+
+ microtime(&sc->sc_if.if_lastchange);
+ break;
+
+#if !defined(__OpenBSD__)
+ case SIOCSIFMTU: /* set interface MTU */
+ if(ifr->ifr_mtu > I4BIPRMAXMTU)
+ error = EINVAL;
+ else if(ifr->ifr_mtu < I4BIPRMINMTU)
+ error = EINVAL;
+ else
+ {
+ ifp->if_mtu = ifr->ifr_mtu;
+ microtime(&sc->sc_if.if_lastchange);
+ }
+ break;
+#endif /* __OPENBSD__ */
+
+#if 0
+ /* not needed for FreeBSD, done in sl_compress_init() (-hm) */
+
+ /* need to add an ioctl: set VJ max slot ID
+ * #define IPRIOCSMAXCID _IOW('I', XXX, int)
+ */
+#ifdef IPR_VJ
+ case IPRIOCSMAXCID:
+ {
+ struct proc *p = curproc; /* XXX */
+ if((error = suser(p->p_ucred, &p->p_acflag)) != 0)
+ return (error);
+ sl_compress_setup(sc->sc_compr, *(int *)data);
+ }
+ break;
+#endif
+#endif
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ splx(s);
+
+ return(error);
+}
+
+/*---------------------------------------------------------------------------*
+ * clear the interface's send queues
+ *---------------------------------------------------------------------------*/
+static void
+iprclearqueues(struct ipr_softc *sc)
+{
+ int x;
+ struct mbuf *m;
+
+ for(;;)
+ {
+ x = splimp();
+ IF_DEQUEUE(&sc->sc_fastq, m);
+ splx(x);
+
+ if(m)
+ m_freem(m);
+ else
+ break;
+ }
+
+ for(;;)
+ {
+ x = splimp();
+ IF_DEQUEUE(&sc->sc_if.if_snd, m);
+ splx(x);
+
+ if(m)
+ m_freem(m);
+ else
+ break;
+ }
+}
+
+#if I4BIPRACCT
+/*---------------------------------------------------------------------------*
+ * watchdog routine
+ *---------------------------------------------------------------------------*/
+static void
+iprwatchdog(struct ifnet *ifp)
+{
+#ifdef __FreeBSD__
+ int unit = ifp->if_unit;
+ struct ipr_softc *sc = &ipr_softc[unit];
+#else
+ struct ipr_softc *sc = ifp->if_softc;
+ int unit = sc->sc_unit;
+#endif
+ bchan_statistics_t bs;
+
+ /* get # of bytes in and out from the HSCX driver */
+
+ (*isdn_linktab[unit]->bch_stat)
+ (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
+
+ sc->sc_ioutb += bs.outbytes;
+ sc->sc_iinb += bs.inbytes;
+
+ if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
+ {
+ int ri = (sc->sc_iinb - sc->sc_linb)/I4BIPRACCTINTVL;
+ int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BIPRACCTINTVL;
+
+ if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
+ sc->sc_fn = 0;
+ else
+ sc->sc_fn = 1;
+
+ sc->sc_linb = sc->sc_iinb;
+ sc->sc_loutb = sc->sc_ioutb;
+
+ i4b_l4_accounting(BDRV_IPR, unit, ACCT_DURING,
+ sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb);
+ }
+ sc->sc_if.if_timer = I4BIPRACCTINTVL;
+}
+#endif /* I4BIPRACCT */
+
+/*===========================================================================*
+ * ISDN INTERFACE ROUTINES
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * start transmitting after connect
+ *---------------------------------------------------------------------------*/
+static void
+i4bipr_connect_startio(int unit)
+{
+ struct ipr_softc *sc = &ipr_softc[unit];
+ int s = SPLI4B();
+
+ if(sc->sc_state == ST_CONNECTED_W)
+ {
+ sc->sc_state = ST_CONNECTED_A;
+ ipr_tx_queue_empty(unit);
+ }
+
+ splx(s);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from L4 handler at connect time
+ *---------------------------------------------------------------------------*/
+static void
+ipr_connect(int unit, void *cdp)
+{
+ struct ipr_softc *sc = &ipr_softc[unit];
+ int s;
+
+ sc->sc_cdp = (call_desc_t *)cdp;
+
+ s = SPLI4B();
+
+ DBGL4(L4_DIALST, "ipr_connect", ("ipr%d: setting dial state to ST_CONNECTED\n", unit));
+
+ sc->sc_if.if_flags |= IFF_RUNNING;
+ sc->sc_state = ST_CONNECTED_W;
+
+ sc->sc_dialresp = DSTAT_NONE;
+ sc->sc_lastdialresp = DSTAT_NONE;
+
+#if I4BIPRACCT
+ sc->sc_iinb = 0;
+ sc->sc_ioutb = 0;
+ sc->sc_inb = 0;
+ sc->sc_outb = 0;
+ sc->sc_linb = 0;
+ sc->sc_loutb = 0;
+ sc->sc_if.if_timer = I4BIPRACCTINTVL;
+#endif
+
+#ifdef I4BIPRADJFRXP
+ sc->sc_first_pkt = 1;
+#endif
+
+ /*
+ * Sometimes ISDN B-channels are switched thru asymmetic. This
+ * means that under such circumstances B-channel data (the first
+ * three packets of a TCP connection in my case) may get lost,
+ * causing a large delay until the connection is started.
+ * When the sending of the very first packet of a TCP connection
+ * is delayed for a to be empirically determined delay (close
+ * to a second in my case) those packets go thru and the TCP
+ * connection comes up "almost" immediately (-hm).
+ */
+
+ if(sc->sc_cdp->isdntxdelay > 0)
+ {
+ timeout((TIMEOUT_FUNC_T)i4bipr_connect_startio, (void *)unit, sc->sc_cdp->isdntxdelay /* hz*1 */);
+ }
+ else
+ {
+ sc->sc_state = ST_CONNECTED_A;
+ ipr_tx_queue_empty(unit);
+ }
+
+ splx(s);
+
+ /* we don't need any negotiation - pass event back right now */
+ i4b_l4_negcomplete(sc->sc_cdp);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from L4 handler at disconnect time
+ *---------------------------------------------------------------------------*/
+static void
+ipr_disconnect(int unit, void *cdp)
+{
+ call_desc_t *cd = (call_desc_t *)cdp;
+ struct ipr_softc *sc = &ipr_softc[unit];
+
+ /* new stuff to check that the active channel is being closed */
+
+ if (cd != sc->sc_cdp)
+ {
+ DBGL4(L4_IPRDBG, "ipr_disconnect", ("ipr%d: channel %d not active\n",
+ cd->driver_unit, cd->channelid));
+ return;
+ }
+
+#if I4BIPRACCT
+ sc->sc_if.if_timer = 0;
+#endif
+
+ i4b_l4_accounting(BDRV_IPR, cd->driver_unit, ACCT_FINAL,
+ sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb);
+
+ sc->sc_cdp = (call_desc_t *)0;
+
+ DBGL4(L4_DIALST, "ipr_disconnect", ("setting dial state to ST_IDLE\n"));
+
+ sc->sc_dialresp = DSTAT_NONE;
+ sc->sc_lastdialresp = DSTAT_NONE;
+
+ sc->sc_if.if_flags &= ~IFF_RUNNING;
+ sc->sc_state = ST_IDLE;
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is used to give a feedback from userland daemon
+ * in case of dial problems
+ *---------------------------------------------------------------------------*/
+static void
+ipr_dialresponse(int unit, int status)
+{
+ struct ipr_softc *sc = &ipr_softc[unit];
+ sc->sc_dialresp = status;
+
+ DBGL4(L4_IPRDBG, "ipr_dialresponse", ("ipr%d: last=%d, this=%d\n",
+ unit, sc->sc_lastdialresp, sc->sc_dialresp));
+}
+
+/*---------------------------------------------------------------------------*
+ * interface soft up/down
+ *---------------------------------------------------------------------------*/
+static void
+ipr_updown(int unit, int updown)
+{
+ struct ipr_softc *sc = &ipr_softc[unit];
+ sc->sc_updown = updown;
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * when a new frame (mbuf) has been received and was put on
+ * the rx queue. It is assumed that this routines runs at
+ * pri level splimp() ! Keep it short !
+ *---------------------------------------------------------------------------*/
+static void
+ipr_rx_data_rdy(int unit)
+{
+ register struct ipr_softc *sc = &ipr_softc[unit];
+ register struct mbuf *m;
+#ifdef IPR_VJ
+#ifdef IPR_VJ_USEBUFFER
+ u_char *cp = sc->sc_cbuf;
+#endif
+ int len, c;
+#endif
+
+ if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
+ return;
+
+ m->m_pkthdr.rcvif = &sc->sc_if;
+
+ m->m_pkthdr.len = m->m_len;
+
+ microtime(&sc->sc_if.if_lastchange);
+
+#ifdef I4BIPRADJFRXP
+
+ /*
+ * The very first packet after the B channel is switched thru
+ * has very often several bytes of random data prepended. This
+ * routine looks where the IP header starts and removes the
+ * the bad data.
+ */
+
+ if(sc->sc_first_pkt)
+ {
+ unsigned char *mp = m->m_data;
+ int i;
+
+ sc->sc_first_pkt = 0;
+
+ for(i = 0; i < m->m_len; i++, mp++)
+ {
+ if( ((*mp & 0xf0) == 0x40) &&
+ ((*mp & 0x0f) >= 0x05) )
+ {
+ m->m_data = mp;
+ m->m_pkthdr.len -= i;
+ break;
+ }
+ }
+ }
+#endif
+
+ sc->sc_if.if_ipackets++;
+ sc->sc_if.if_ibytes += m->m_pkthdr.len;
+
+#ifdef IPR_VJ
+ if((c = (*(mtod(m, u_char *)) & 0xf0)) != (IPVERSION << 4))
+ {
+ /* copy data to buffer */
+
+ len = m->m_len;
+
+#ifdef IPR_VJ_USEBUFFER
+/* XXX */ m_copydata(m, 0, len, cp);
+#endif
+
+ if(c & 0x80)
+ {
+ c = TYPE_COMPRESSED_TCP;
+ }
+ else if(c == TYPE_UNCOMPRESSED_TCP)
+ {
+#ifdef IPR_VJ_USEBUFFER
+ *cp &= 0x4f; /* XXX */
+#else
+ *(mtod(m, u_char *)) &= 0x4f;
+#endif
+ }
+
+ /*
+ * We've got something that's not an IP packet.
+ * If compression is enabled, try to decompress it.
+ * Otherwise, if `auto-enable' compression is on and
+ * it's a reasonable packet, decompress it and then
+ * enable compression. Otherwise, drop it.
+ */
+ if(sc->sc_if.if_flags & IPR_COMPRESS)
+ {
+#ifdef IPR_VJ_USEBUFFER
+ len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
+#else
+ len = sl_uncompress_tcp((u_char **)&m->m_data, len,
+ (u_int)c, &sc->sc_compr);
+#endif
+
+ if(len <= 0)
+ {
+#ifdef DEBUG_IPR_VJ
+ printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_COMPRESS!\n");
+#endif
+ goto error;
+ }
+ }
+ else if((sc->sc_if.if_flags & IPR_AUTOCOMP) &&
+ (c == TYPE_UNCOMPRESSED_TCP) && (len >= 40))
+ {
+#ifdef IPR_VJ_USEBUFFER
+ len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
+#else
+ len = sl_uncompress_tcp((u_char **)&m->m_data, len,
+ (u_int)c, &sc->sc_compr);
+#endif
+
+ if(len <= 0)
+ {
+#ifdef DEBUG_IPR_VJ
+ printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_AUTOCOMP!\n");
+#endif
+ goto error;
+ }
+
+ sc->sc_if.if_flags |= IPR_COMPRESS;
+ }
+ else
+ {
+#ifdef DEBUG_IPR_VJ
+ printf("i4b_ipr, ipr_input: invalid ip packet!\n");
+#endif
+
+error:
+ sc->sc_if.if_ierrors++;
+ sc->sc_if.if_collisions++;
+ m_freem(m);
+ return;
+ }
+#ifdef IPR_VJ_USEBUFFER
+/* XXX */ m_copyback(m, 0, len, cp);
+#else
+ m->m_len = m->m_pkthdr.len = len;
+#endif
+ }
+#endif
+
+#if I4BIPRACCT
+ /* NB. do the accounting after decompression! */
+ sc->sc_inb += m->m_pkthdr.len;
+#endif
+
+#if NBPFILTER > 0
+ if(sc->sc_if.if_bpf)
+ {
+ /* prepend the address family as a four byte field */
+ struct mbuf mm;
+ u_int af = AF_INET;
+ mm.m_next = m;
+ mm.m_len = 4;
+ mm.m_data = (char *)&af;
+
+#ifdef __FreeBSD__
+ bpf_mtap(&sc->sc_if, &mm);
+#else
+ bpf_mtap(sc->sc_if.if_bpf, &mm);
+#endif
+ }
+#endif /* NBPFILTER > 0 */
+
+ if(IF_QFULL(&ipintrq))
+ {
+ DBGL4(L4_IPRDBG, "ipr_rx_data_rdy", ("ipr%d: ipintrq full!\n", unit));
+
+ IF_DROP(&ipintrq);
+ sc->sc_if.if_ierrors++;
+ sc->sc_if.if_iqdrops++;
+ m_freem(m);
+ }
+ else
+ {
+ IF_ENQUEUE(&ipintrq, m);
+ schednetisr(NETISR_IP);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * when the last frame has been sent out and there is no
+ * further frame (mbuf) in the tx queue.
+ *---------------------------------------------------------------------------*/
+static void
+ipr_tx_queue_empty(int unit)
+{
+ register struct ipr_softc *sc = &ipr_softc[unit];
+ register struct mbuf *m;
+#ifdef IPR_VJ
+ struct ip *ip;
+#endif
+ int x = 0;
+
+ if(sc->sc_state != ST_CONNECTED_A)
+ return;
+
+ for(;;)
+ {
+ IF_DEQUEUE(&sc->sc_fastq, m);
+ if(m)
+ {
+ sc->sc_if.if_omcasts++;
+ }
+ else
+ {
+ IF_DEQUEUE(&sc->sc_if.if_snd, m);
+ if(m == NULL)
+ break;
+ }
+
+ microtime(&sc->sc_if.if_lastchange);
+
+#if NBPFILTER > 0
+ if(sc->sc_if.if_bpf)
+ {
+ /* prepend the address family as a four byte field */
+
+ struct mbuf mm;
+ u_int af = AF_INET;
+ mm.m_next = m;
+ mm.m_len = 4;
+ mm.m_data = (char *)&af;
+
+#ifdef __FreeBSD__
+ bpf_mtap(&sc->sc_if, &mm);
+#else
+ bpf_mtap(sc->sc_if.if_bpf, &mm);
+#endif
+ }
+#endif /* NBPFILTER */
+
+#if I4BIPRACCT
+ sc->sc_outb += m->m_pkthdr.len; /* size before compression */
+#endif
+
+#ifdef IPR_VJ
+ if((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP)
+ {
+ if(sc->sc_if.if_flags & IPR_COMPRESS)
+ {
+ *mtod(m, u_char *) |= sl_compress_tcp(m, ip,
+ &sc->sc_compr, 1);
+ }
+ }
+#endif
+ x = 1;
+
+ IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
+
+ sc->sc_if.if_obytes += m->m_pkthdr.len;
+
+ sc->sc_if.if_opackets++;
+ }
+
+ if(x)
+ (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * each time a packet is received or transmitted. It should
+ * be used to implement an activity timeout mechanism.
+ *---------------------------------------------------------------------------*/
+static void
+ipr_activity(int unit, int rxtx)
+{
+ ipr_softc[unit].sc_cdp->last_active_time = SECOND;
+}
+
+/*---------------------------------------------------------------------------*
+ * return this drivers linktab address
+ *---------------------------------------------------------------------------*/
+drvr_link_t *
+ipr_ret_linktab(int unit)
+{
+ return(&ipr_drvr_linktab[unit]);
+}
+
+/*---------------------------------------------------------------------------*
+ * setup the isdn_linktab for this driver
+ *---------------------------------------------------------------------------*/
+void
+ipr_set_linktab(int unit, isdn_link_t *ilt)
+{
+ isdn_linktab[unit] = ilt;
+}
+
+/*---------------------------------------------------------------------------*
+ * initialize this drivers linktab
+ *---------------------------------------------------------------------------*/
+static void
+ipr_init_linktab(int unit)
+{
+ ipr_drvr_linktab[unit].unit = unit;
+ ipr_drvr_linktab[unit].bch_rx_data_ready = ipr_rx_data_rdy;
+ ipr_drvr_linktab[unit].bch_tx_queue_empty = ipr_tx_queue_empty;
+ ipr_drvr_linktab[unit].bch_activity = ipr_activity;
+ ipr_drvr_linktab[unit].line_connected = ipr_connect;
+ ipr_drvr_linktab[unit].line_disconnected = ipr_disconnect;
+ ipr_drvr_linktab[unit].dial_response = ipr_dialresponse;
+ ipr_drvr_linktab[unit].updown_ind = ipr_updown;
+}
+
+/*===========================================================================*/
+
+#endif /* NI4BIPR > 0 */
diff --git a/sys/i4b/driver/i4b_isppp.c b/sys/i4b/driver/i4b_isppp.c
new file mode 100644
index 0000000..b1cb2cf
--- /dev/null
+++ b/sys/i4b/driver/i4b_isppp.c
@@ -0,0 +1,710 @@
+/*
+ * Copyright (c) 1997 Joerg Wunsch. All rights reserved.
+ *
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_isppp.c - isdn4bsd kernel SyncPPP driver
+ * --------------------------------------------
+ *
+ * Uses Serge Vakulenko's sppp backend (originally contributed with
+ * the "cx" driver for Cronyx's HDLC-in-hardware device). This driver
+ * is only the glue between sppp and i4b.
+ *
+ * $Id: i4b_isppp.c,v 1.20 1998/12/18 14:20:44 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 11:47:58 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "i4bisppp.h"
+#ifdef __FreeBSD__
+#include "sppp.h"
+#endif
+
+#if NI4BISPPP == 0
+# error "You need to define `pseudo-device sppp <N>' with options ISPPP"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/ioccom.h>
+#include <sys/sockio.h>
+#include <sys/kernel.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#ifdef __FreeBSD__
+#include <net/if_sppp.h>
+#else
+#include <i4b/sppp/if_sppp.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <sys/time.h>
+#include <net/bpf.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_cause.h>
+#else
+#include <i4b/i4b_ioctl.h>
+#include <i4b/i4b_cause.h>
+#endif
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_l3l4.h>
+
+#include <i4b/layer4/i4b_l4.h>
+
+#ifdef __FreeBSD__
+#define ISPPP_FMT "isp%d: "
+#define ISPPP_ARG(sc) ((sc)->sc_if.if_unit)
+#define PDEVSTATIC static
+#define IFP2UNIT(ifp) (ifp)->if_unit
+
+# if __FreeBSD_version >= 300001
+# define CALLOUT_INIT(chan) callout_handle_init(chan)
+# define TIMEOUT(fun, arg, chan, tick) chan = timeout(fun, arg, tick)
+# define UNTIMEOUT(fun, arg, chan) untimeout(fun, arg, chan)
+# define IOCTL_CMD_T u_long
+# else
+# define CALLOUT_INIT(chan) do {} while(0)
+# define TIMEOUT(fun, arg, chan, tick) timeout(fun, arg, tick)
+# define UNTIMEOUT(fun, arg, chan) untimeout(fun, arg)
+# define IOCTL_CMD_T int
+# endif
+
+#elif defined __NetBSD__ || defined __OpenBSD__
+#define ISPPP_FMT "%s: "
+#define ISPPP_ARG(sc) ((sc)->sc_if.if_xname)
+#define PDEVSTATIC /* not static */
+#define IOCTL_CMD_T u_long
+#define IFP2UNIT(ifp) ((struct i4bisppp_softc *)ifp->if_softc)->sc_unit
+#else
+# error "What system are you using?"
+#endif
+
+#ifdef __FreeBSD__
+PDEVSTATIC void i4bispppattach(void *);
+PSEUDO_SET(i4bispppattach, i4b_isppp);
+#else
+PDEVSTATIC void i4bispppattach __P((void));
+#endif
+
+#define I4BISPPPACCT 1 /* enable accounting messages */
+#define I4BISPPPACCTINTVL 2 /* accounting msg interval in secs */
+#define I4BISPPPDISCDEBUG 1
+
+#define PPP_HDRLEN 4 /* 4 octetts PPP header length */
+
+struct i4bisppp_softc {
+ /*
+ * struct sppp starts with a struct ifnet, but we gotta allocate
+ * more space for it. NB: do not relocate this union, it must
+ * be first in isppp_softc. The tls and tlf hooks below want to
+ * convert a ``struct sppp *'' into a ``struct isppp_softc *''.
+ */
+ union {
+ struct ifnet scu_if;
+ struct sppp scu_sp;
+ } sc_if_un;
+#define sc_if sc_if_un.scu_if
+
+ int sc_state; /* state of the interface */
+
+#ifndef __FreeBSD__
+ int sc_unit; /* unit number for Net/OpenBSD */
+#endif
+
+ call_desc_t *sc_cdp; /* ptr to call descriptor */
+
+#ifdef I4BISPPPACCT
+ int sc_iinb; /* isdn driver # of inbytes */
+ int sc_ioutb; /* isdn driver # of outbytes */
+ int sc_inb; /* # of bytes rx'd */
+ int sc_outb; /* # of bytes tx'd */
+ int sc_linb; /* last # of bytes rx'd */
+ int sc_loutb; /* last # of bytes tx'd */
+ int sc_fn; /* flag, first null acct */
+#endif
+
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ struct callout_handle sc_ch;
+#endif
+
+} i4bisppp_softc[NI4BISPPP];
+
+static void i4bisppp_init_linktab(int unit);
+static int i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data);
+
+#if 0
+static void i4bisppp_send(struct ifnet *ifp);
+#endif
+
+static void i4bisppp_start(struct ifnet *ifp);
+
+#if 0 /* never used ??? */
+static void i4bisppp_timeout(void *cookie);
+#endif
+
+static void i4bisppp_tls(struct sppp *sp);
+static void i4bisppp_tlf(struct sppp *sp);
+static void i4bisppp_state_changed(struct sppp *sp, int new_state);
+static void i4bisppp_negotiation_complete(struct sppp *sp);
+static void i4bisppp_watchdog(struct ifnet *ifp);
+
+/* initialized by L4 */
+
+static drvr_link_t i4bisppp_drvr_linktab[NI4BISPPP];
+static isdn_link_t *isdn_linktab[NI4BISPPP];
+
+enum i4bisppp_states {
+ ST_IDLE, /* initialized, ready, idle */
+ ST_DIALING, /* dialling out to remote */
+ ST_CONNECTED, /* connected to remote */
+};
+
+/*===========================================================================*
+ * DEVICE DRIVER ROUTINES
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * interface attach routine at kernel boot time
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC void
+#ifdef __FreeBSD__
+i4bispppattach(void *dummy)
+#else
+i4bispppattach(void)
+#endif
+{
+ struct i4bisppp_softc *sc = i4bisppp_softc;
+ int i;
+
+#ifndef HACK_NO_PSEUDO_ATTACH_MSG
+ printf("i4bisppp: %d ISDN SyncPPP device(s) attached\n",
+ NI4BISPPP);
+#endif
+
+ for(i = 0; i < NI4BISPPP; sc++, i++) {
+ i4bisppp_init_linktab(i);
+
+ sc->sc_if.if_softc = sc;
+
+#ifdef __FreeBSD__
+ sc->sc_if.if_name = "isp";
+#if defined(__FreeBSD_version) && __FreeBSD_version < 300001
+ sc->sc_if.if_next = NULL;
+#endif
+ sc->sc_if.if_unit = i;
+#else
+ sprintf(sc->sc_if.if_xname, "isp%d", i);
+ sc->sc_unit = i;
+#endif
+
+ sc->sc_if.if_mtu = PP_MTU;
+ sc->sc_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT;
+ sc->sc_if.if_type = IFT_ISDNBASIC;
+ sc->sc_state = ST_IDLE;
+
+ sc->sc_if.if_ioctl = i4bisppp_ioctl;
+
+ /* actually initialized by sppp_attach() */
+ /* sc->sc_if.if_output = sppp_output; */
+
+ sc->sc_if.if_start = i4bisppp_start;
+
+ sc->sc_if.if_hdrlen = 0;
+ sc->sc_if.if_addrlen = 0;
+ sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
+
+ sc->sc_if.if_ipackets = 0;
+ sc->sc_if.if_ierrors = 0;
+ sc->sc_if.if_opackets = 0;
+ sc->sc_if.if_oerrors = 0;
+ sc->sc_if.if_collisions = 0;
+ sc->sc_if.if_ibytes = 0;
+ sc->sc_if.if_obytes = 0;
+ sc->sc_if.if_imcasts = 0;
+ sc->sc_if.if_omcasts = 0;
+ sc->sc_if.if_iqdrops = 0;
+ sc->sc_if.if_noproto = 0;
+
+#if I4BISPPPACCT
+ sc->sc_if.if_timer = 0;
+ sc->sc_if.if_watchdog = i4bisppp_watchdog;
+ sc->sc_iinb = 0;
+ sc->sc_ioutb = 0;
+ sc->sc_inb = 0;
+ sc->sc_outb = 0;
+ sc->sc_linb = 0;
+ sc->sc_loutb = 0;
+ sc->sc_fn = 1;
+#endif
+
+ sc->sc_if_un.scu_sp.pp_tls = i4bisppp_tls;
+ sc->sc_if_un.scu_sp.pp_tlf = i4bisppp_tlf;
+ sc->sc_if_un.scu_sp.pp_con = i4bisppp_negotiation_complete;
+ sc->sc_if_un.scu_sp.pp_chg = i4bisppp_state_changed;
+
+ sppp_attach(&sc->sc_if);
+ if_attach(&sc->sc_if);
+
+#if NBPFILTER > 0
+#ifdef __FreeBSD__
+ bpfattach(&sc->sc_if, DLT_PPP, PPP_HDRLEN);
+ CALLOUT_INIT(&sc->sc_ch);
+#endif /* __FreeBSD__ */
+#ifdef __NetBSD__
+ bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_PPP, sizeof(u_int));
+#endif
+#endif
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * process ioctl
+ *---------------------------------------------------------------------------*/
+static int
+i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data)
+{
+ struct i4bisppp_softc *sc = ifp->if_softc;
+#if 0
+ struct sppp *sp = (struct sppp *)sc;
+ struct ifaddr *ifa = (struct ifaddr *) data;
+ struct ifreq *ifr = (struct ifreq *) data;
+#endif
+
+ int error;
+
+ error = sppp_ioctl(&sc->sc_if, cmd, data);
+ if (error)
+ return error;
+
+ switch(cmd) {
+ case SIOCSIFFLAGS:
+#if 0 /* never used ??? */
+ x = splimp();
+ if ((ifp->if_flags & IFF_UP) == 0)
+ UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch);
+ splx(x);
+#endif
+ break;
+ }
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*
+ * start output to ISDN B-channel
+ *---------------------------------------------------------------------------*/
+static void
+i4bisppp_start(struct ifnet *ifp)
+{
+ struct i4bisppp_softc *sc = ifp->if_softc;
+ struct mbuf *m;
+ int s;
+ int unit = IFP2UNIT(ifp);
+
+ if (sppp_isempty(ifp))
+ return;
+
+ if(sc->sc_state != ST_CONNECTED)
+ return;
+
+ s = splimp();
+ /*ifp->if_flags |= IFF_OACTIVE; - need to clear this somewhere */
+ splx(s);
+
+ while ((m = sppp_dequeue(&sc->sc_if)) != NULL)
+ {
+
+#if NBPFILTER > 0
+#ifdef __FreeBSD__
+ if (ifp->if_bpf)
+ bpf_mtap(ifp, m);
+#endif /* __FreeBSD__ */
+
+#ifdef __NetBSD__
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+#endif /* NBPFILTER > 0 */
+
+ microtime(&ifp->if_lastchange);
+
+ IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
+
+ sc->sc_if.if_obytes += m->m_pkthdr.len;
+ sc->sc_outb += m->m_pkthdr.len;
+ sc->sc_if.if_opackets++;
+ }
+ isdn_linktab[unit]->bch_tx_start(isdn_linktab[unit]->unit,
+ isdn_linktab[unit]->channel);
+}
+
+#ifdef I4BISPPPACCT
+/*---------------------------------------------------------------------------*
+ * watchdog routine
+ *---------------------------------------------------------------------------*/
+static void
+i4bisppp_watchdog(struct ifnet *ifp)
+{
+ struct i4bisppp_softc *sc = ifp->if_softc;
+ int unit = IFP2UNIT(ifp);
+ bchan_statistics_t bs;
+
+ (*isdn_linktab[unit]->bch_stat)
+ (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
+
+ sc->sc_ioutb += bs.outbytes;
+ sc->sc_iinb += bs.inbytes;
+
+ if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
+ {
+ int ri = (sc->sc_iinb - sc->sc_linb)/I4BISPPPACCTINTVL;
+ int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BISPPPACCTINTVL;
+
+ if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
+ sc->sc_fn = 0;
+ else
+ sc->sc_fn = 1;
+
+ sc->sc_linb = sc->sc_iinb;
+ sc->sc_loutb = sc->sc_ioutb;
+
+ i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_DURING,
+ sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb);
+ }
+ sc->sc_if.if_timer = I4BISPPPACCTINTVL;
+
+#if 0 /* old stuff, keep it around */
+ printf(ISPPP_FMT "transmit timeout\n", ISPPP_ARG(sc));
+ i4bisppp_start(ifp);
+#endif
+}
+#endif /* I4BISPPPACCT */
+
+/*
+ *===========================================================================*
+ * SyncPPP layer interface routines
+ *===========================================================================*
+ */
+
+#if 0 /* never used ??? */
+/*---------------------------------------------------------------------------*
+ * just an alias for i4bisppp_tls, but of type timeout_t
+ *---------------------------------------------------------------------------*/
+static void
+i4bisppp_timeout(void *cookie)
+{
+ i4bisppp_tls((struct sppp *)cookie);
+}
+#endif
+
+/*---------------------------------------------------------------------------*
+ * PPP this-layer-started action
+ *---------------------------------------------------------------------------*
+ */
+static void
+i4bisppp_tls(struct sppp *sp)
+{
+ struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
+ struct ifnet *ifp = (struct ifnet *)sp;
+
+ if(sc->sc_state == ST_CONNECTED)
+ return;
+
+ i4b_l4_dialout(BDRV_ISPPP, IFP2UNIT(ifp));
+}
+
+/*---------------------------------------------------------------------------*
+ * PPP this-layer-finished action
+ *---------------------------------------------------------------------------*
+ */
+static void
+i4bisppp_tlf(struct sppp *sp)
+{
+ struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
+/* call_desc_t *cd = sc->sc_cdp; */
+ struct ifnet *ifp = (struct ifnet *)sp;
+
+ if(sc->sc_state != ST_CONNECTED)
+ return;
+
+#if 0 /* never used ??? */
+ UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch);
+#endif
+
+ i4b_l4_drvrdisc(BDRV_ISPPP, IFP2UNIT(ifp));
+}
+/*---------------------------------------------------------------------------*
+ * PPP interface phase change
+ *---------------------------------------------------------------------------*
+ */
+static void
+i4bisppp_state_changed(struct sppp *sp, int new_state)
+{
+ struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
+
+ i4b_l4_ifstate_changed(sc->sc_cdp, new_state);
+}
+
+/*---------------------------------------------------------------------------*
+ * PPP control protocol negotiation complete (run ip-up script now)
+ *---------------------------------------------------------------------------*
+ */
+static void
+i4bisppp_negotiation_complete(struct sppp *sp)
+{
+ struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp;
+
+ i4b_l4_negcomplete(sc->sc_cdp);
+}
+
+/*===========================================================================*
+ * ISDN INTERFACE ROUTINES
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from L4 handler at connect time
+ *---------------------------------------------------------------------------*/
+static void
+i4bisppp_connect(int unit, void *cdp)
+{
+ struct i4bisppp_softc *sc = &i4bisppp_softc[unit];
+ struct sppp *sp = &sc->sc_if_un.scu_sp;
+ int s = splimp();
+
+ sc->sc_cdp = (call_desc_t *)cdp;
+ sc->sc_state = ST_CONNECTED;
+
+#if I4BISPPPACCT
+ sc->sc_iinb = 0;
+ sc->sc_ioutb = 0;
+ sc->sc_inb = 0;
+ sc->sc_outb = 0;
+ sc->sc_linb = 0;
+ sc->sc_loutb = 0;
+ sc->sc_if.if_timer = I4BISPPPACCTINTVL;
+#endif
+
+#if 0 /* never used ??? */
+ UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch);
+#endif
+
+ sp->pp_up(sp); /* tell PPP we are ready */
+
+ splx(s);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from L4 handler at disconnect time
+ *---------------------------------------------------------------------------*/
+static void
+i4bisppp_disconnect(int unit, void *cdp)
+{
+ call_desc_t *cd = (call_desc_t *)cdp;
+ struct i4bisppp_softc *sc = &i4bisppp_softc[unit];
+ struct sppp *sp = &sc->sc_if_un.scu_sp;
+
+ int s = splimp();
+
+ /* new stuff to check that the active channel is being closed */
+ if (cd != sc->sc_cdp)
+ {
+#ifdef I4BISPPPDISCDEBUG
+ printf("i4bisppp_disconnect: isppp%d channel%d not active\n",
+ cd->driver_unit, cd->channelid);
+#endif
+ splx(s);
+ return;
+ }
+
+#if I4BISPPPACCT
+ sc->sc_if.if_timer = 0;
+#endif
+
+ i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_FINAL,
+ sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb);
+
+ if (sc->sc_state == ST_CONNECTED)
+ {
+#if 0 /* never used ??? */
+ UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch);
+#endif
+ sc->sc_cdp = (call_desc_t *)0;
+ /* do thhis here because pp_down calls i4bisppp_tlf */
+ sc->sc_state = ST_IDLE;
+ sp->pp_down(sp); /* tell PPP we have hung up */
+ }
+
+ splx(s);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is used to give a feedback from userland demon
+ * in case of dial problems
+ *---------------------------------------------------------------------------*/
+static void
+i4bisppp_dialresponse(int unit, int status)
+{
+/* struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; */
+}
+
+/*---------------------------------------------------------------------------*
+ * interface up/down
+ *---------------------------------------------------------------------------*/
+static void
+i4bisppp_updown(int unit, int updown)
+{
+ /* could probably do something useful here */
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * when a new frame (mbuf) has been received and was put on
+ * the rx queue.
+ *---------------------------------------------------------------------------*/
+static void
+i4bisppp_rx_data_rdy(int unit)
+{
+ struct i4bisppp_softc *sc = &i4bisppp_softc[unit];
+ struct mbuf *m;
+ int s;
+
+ if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
+ return;
+
+ m->m_pkthdr.rcvif = &sc->sc_if;
+ m->m_pkthdr.len = m->m_len;
+
+ microtime(&sc->sc_if.if_lastchange);
+
+ sc->sc_if.if_ipackets++;
+ sc->sc_if.if_ibytes += m->m_pkthdr.len;
+
+#if I4BISPPPACCT
+ sc->sc_inb += m->m_pkthdr.len;
+#endif
+
+#ifdef I4BISPPPDEBUG
+ printf("i4bisppp_rx_data_ready: received packet!\n");
+#endif
+
+#if NBPFILTER > 0
+
+#ifdef __FreeBSD__
+ if(sc->sc_if.if_bpf)
+ bpf_mtap(&sc->sc_if, m);
+#endif /* __FreeBSD__ */
+
+#ifdef __NetBSD__
+ if(sc->sc_if.if_bpf)
+ bpf_mtap(sc->sc_if.if_bpf, m);
+#endif
+
+#endif /* NBPFILTER > 0 */
+
+ s = splimp();
+
+ sppp_input(&sc->sc_if, m);
+
+ splx(s);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * when the last frame has been sent out and there is no
+ * further frame (mbuf) in the tx queue.
+ *---------------------------------------------------------------------------*/
+static void
+i4bisppp_tx_queue_empty(int unit)
+{
+ i4bisppp_start(&i4bisppp_softc[unit].sc_if);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * each time a packet is received or transmitted. It should
+ * be used to implement an activity timeout mechanism.
+ *---------------------------------------------------------------------------*/
+static void
+i4bisppp_activity(int unit, int rxtx)
+{
+ i4bisppp_softc[unit].sc_cdp->last_active_time = SECOND;
+}
+
+/*---------------------------------------------------------------------------*
+ * return this drivers linktab address
+ *---------------------------------------------------------------------------*/
+drvr_link_t *
+i4bisppp_ret_linktab(int unit)
+{
+ return(&i4bisppp_drvr_linktab[unit]);
+}
+
+/*---------------------------------------------------------------------------*
+ * setup the isdn_linktab for this driver
+ *---------------------------------------------------------------------------*/
+void
+i4bisppp_set_linktab(int unit, isdn_link_t *ilt)
+{
+ isdn_linktab[unit] = ilt;
+}
+
+/*---------------------------------------------------------------------------*
+ * initialize this drivers linktab
+ *---------------------------------------------------------------------------*/
+static void
+i4bisppp_init_linktab(int unit)
+{
+ i4bisppp_drvr_linktab[unit].unit = unit;
+ i4bisppp_drvr_linktab[unit].bch_rx_data_ready = i4bisppp_rx_data_rdy;
+ i4bisppp_drvr_linktab[unit].bch_tx_queue_empty = i4bisppp_tx_queue_empty;
+ i4bisppp_drvr_linktab[unit].bch_activity = i4bisppp_activity;
+ i4bisppp_drvr_linktab[unit].line_connected = i4bisppp_connect;
+ i4bisppp_drvr_linktab[unit].line_disconnected = i4bisppp_disconnect;
+ i4bisppp_drvr_linktab[unit].dial_response = i4bisppp_dialresponse;
+ i4bisppp_drvr_linktab[unit].updown_ind = i4bisppp_updown;
+}
+
+/*===========================================================================*/
diff --git a/sys/i4b/driver/i4b_rbch.c b/sys/i4b/driver/i4b_rbch.c
new file mode 100644
index 0000000..9cf432c
--- /dev/null
+++ b/sys/i4b/driver/i4b_rbch.c
@@ -0,0 +1,820 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_rbch.c - device driver for raw B channel data
+ * ---------------------------------------------------
+ *
+ * $Id: i4b_rbch.c,v 1.23 1998/12/14 09:39:10 hm Exp $
+ *
+ * last edit-date: [Sun Dec 13 10:19:08 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "i4brbch.h"
+
+#if NI4BRBCH > 0
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#if (defined(__FreeBSD_version) && __FreeBSD_version >= 300001) || !defined(__FreeBSD__)
+#include <sys/ioccom.h>
+#include <sys/poll.h>
+#else
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#endif
+
+#if (defined(__FreeBSD_version) && __FreeBSD_version >= 300001)
+#include <sys/filio.h>
+#endif
+
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+
+#ifdef __NetBSD__
+extern cc_t ttydefchars;
+#define termioschars(t) memcpy((t)->c_cc, &ttydefchars, sizeof((t)->c_cc))
+#endif
+
+#ifdef __FreeBSD__
+#include "opt_devfs.h"
+#endif
+
+#ifdef DEVFS
+#include <sys/devfsext.h>
+#endif
+
+#ifdef __NetBSD__
+#include <sys/filio.h>
+#define bootverbose 0
+#endif
+
+#ifdef __FreeBSD__
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_debug.h>
+#else
+#include <i4b/i4b_ioctl.h>
+#include <i4b/i4b_debug.h>
+#endif
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_l3l4.h>
+
+#include <i4b/layer4/i4b_l4.h>
+/* initialized by L4 */
+
+static drvr_link_t rbch_drvr_linktab[NI4BRBCH];
+static isdn_link_t *isdn_linktab[NI4BRBCH];
+
+static struct rbch_softc {
+ int sc_devstate; /* state of driver */
+#define ST_IDLE 0x00
+#define ST_CONNECTED 0x01
+#define ST_ISOPEN 0x02
+#define ST_RDWAITDATA 0x04
+#define ST_WRWAITEMPTY 0x08
+#define ST_NOBLOCK 0x10
+
+ int sc_bprot; /* B-ch protocol used */
+
+ call_desc_t *cd; /* Call Descriptor */
+ struct termios it_in;
+
+ struct ifqueue sc_hdlcq; /* hdlc read queue */
+#define I4BRBCHMAXQLEN 10
+
+ struct selinfo selp; /* select / poll */
+
+#ifdef DEVFS
+ void *devfs_token; /* device filesystem */
+#endif
+} rbch_softc[NI4BRBCH];
+
+static void rbch_rx_data_rdy(int unit);
+static void rbch_tx_queue_empty(int unit);
+static void rbch_connect(int unit, void *cdp);
+static void rbch_disconnect(int unit, void *cdp);
+static void rbch_init_linktab(int unit);
+static void rbch_clrq(int unit);
+
+#ifndef __FreeBSD__
+#define PDEVSTATIC /* - not static - */
+#define IOCTL_CMD_T u_long
+void i4brbchattach __P((void));
+int i4brbchopen __P((dev_t dev, int flag, int fmt, struct proc *p));
+int i4brbchclose __P((dev_t dev, int flag, int fmt, struct proc *p));
+int i4brbchread __P((dev_t dev, struct uio *uio, int ioflag));
+int i4brbchwrite __P((dev_t dev, struct uio *uio, int ioflag));
+int i4brbchioctl __P((dev_t dev, IOCTL_CMD_T cmd, caddr_t arg, int flag, struct proc* pr));
+int i4brbchpoll __P((dev_t dev, int events, struct proc *p));
+#endif
+
+#if BSD > 199306 && defined(__FreeBSD__)
+#define PDEVSTATIC static
+#if !defined(__FreeBSD_version) || __FreeBSD_version < 300003
+#define IOCTL_CMD_T int
+#else
+#define IOCTL_CMD_T u_long
+#endif
+
+PDEVSTATIC d_open_t i4brbchopen;
+PDEVSTATIC d_close_t i4brbchclose;
+PDEVSTATIC d_read_t i4brbchread;
+PDEVSTATIC d_read_t i4brbchwrite;
+PDEVSTATIC d_ioctl_t i4brbchioctl;
+
+#if (defined(__FreeBSD_version) && __FreeBSD_version >= 300001) || !defined(__FreeBSD__)
+PDEVSTATIC d_poll_t i4brbchpoll;
+#else
+PDEVSTATIC d_select_t i4brbchselect;
+#endif
+
+#define CDEV_MAJOR 57
+static struct cdevsw i4brbch_cdevsw = {
+ i4brbchopen, i4brbchclose, i4brbchread, i4brbchwrite,
+ i4brbchioctl, nostop, noreset, nodevtotty,
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ i4brbchpoll, nommap, NULL, "i4brbch", NULL, -1
+#else
+ i4brbchselect, nommap, NULL, "i4brbch", NULL, -1
+#endif
+};
+
+static void i4brbchattach(void *);
+PSEUDO_SET(i4brbchattach, i4b_rbch);
+
+/*===========================================================================*
+ * DEVICE DRIVER ROUTINES
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * initialization at kernel load time
+ *---------------------------------------------------------------------------*/
+static void
+i4brbchinit(void *unused)
+{
+ dev_t dev;
+
+ dev = makedev(CDEV_MAJOR, 0);
+
+ cdevsw_add(&dev, &i4brbch_cdevsw, NULL);
+}
+
+SYSINIT(i4brbchdev, SI_SUB_DRIVERS,
+ SI_ORDER_MIDDLE+CDEV_MAJOR, &i4brbchinit, NULL);
+
+#endif /* BSD > 199306 && defined(__FreeBSD__) */
+
+/*---------------------------------------------------------------------------*
+ * interface attach routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC void
+#ifdef __FreeBSD__
+i4brbchattach(void *dummy)
+#else
+i4brbchattach()
+#endif
+{
+ int i;
+
+#ifndef HACK_NO_PSEUDO_ATTACH_MSG
+ printf("i4brbch: %d raw B channel access device(s) attached\n", NI4BRBCH);
+#endif
+
+ for(i=0; i < NI4BRBCH; i++)
+ {
+#ifdef DEVFS
+ rbch_softc[i].devfs_token =
+ devfs_add_devswf(&i4brbch_cdevsw, i, DV_CHR,
+ UID_ROOT, GID_WHEEL, 0600,
+ "i4brbch%d", i);
+#endif
+ rbch_softc[i].sc_devstate = ST_IDLE;
+ rbch_softc[i].sc_hdlcq.ifq_maxlen = I4BRBCHMAXQLEN;
+ rbch_softc[i].it_in.c_ispeed = rbch_softc[i].it_in.c_ospeed = 64000;
+ termioschars(&rbch_softc[i].it_in);
+ rbch_init_linktab(i);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * open rbch device
+ *---------------------------------------------------------------------------*/
+int
+i4brbchopen(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int unit = minor(dev);
+
+ if(unit > NI4BRBCH)
+ return(ENXIO);
+
+ if(rbch_softc[unit].sc_devstate & ST_ISOPEN)
+ return(EBUSY);
+
+ rbch_clrq(unit);
+
+ rbch_softc[unit].sc_devstate |= ST_ISOPEN;
+
+ DBGL4(L4_RBCHDBG, "i4brbchopen", ("unit %d, open\n", unit));
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * close rbch device
+ *---------------------------------------------------------------------------*/
+int
+i4brbchclose(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int unit = minor(dev);
+
+ if (rbch_softc[unit].cd) {
+ i4b_l4_disconnect_ind(rbch_softc[unit].cd);
+ rbch_softc[unit].cd = NULL;
+ }
+ rbch_softc[unit].sc_devstate &= ~ST_ISOPEN;
+
+ rbch_clrq(unit);
+
+ DBGL4(L4_RBCHDBG, "i4brbclose", ("unit %d, close\n", unit));
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * read from rbch device
+ *---------------------------------------------------------------------------*/
+int
+i4brbchread(dev_t dev, struct uio *uio, int ioflag)
+{
+ struct mbuf *m;
+ int s;
+ int error = 0;
+ int unit = minor(dev);
+ struct ifqueue *iqp;
+
+ DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, enter read\n", unit));
+
+ if(!(rbch_softc[unit].sc_devstate & ST_ISOPEN))
+ {
+ DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, read while not open\n", unit));
+ return(EIO);
+ }
+
+ if((rbch_softc[unit].sc_devstate & ST_NOBLOCK)) {
+ if(!(rbch_softc[unit].sc_devstate & ST_CONNECTED))
+ return(EWOULDBLOCK);
+
+ if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
+ iqp = &rbch_softc[unit].sc_hdlcq;
+ else
+ iqp = isdn_linktab[unit]->rx_queue;
+
+ if(IF_QEMPTY(iqp) && (rbch_softc[unit].sc_devstate & ST_ISOPEN))
+ return(EWOULDBLOCK);
+ } else {
+ while(!(rbch_softc[unit].sc_devstate & ST_CONNECTED))
+ {
+ DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, wait read init\n", unit));
+
+ if((error = tsleep((caddr_t) &rbch_softc[unit],
+ TTIPRI | PCATCH,
+ "rrrbch", 0 )) != 0)
+ {
+ DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, error %d tsleep\n", unit, error));
+ return(error);
+ }
+ }
+
+ if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
+ iqp = &rbch_softc[unit].sc_hdlcq;
+ else
+ iqp = isdn_linktab[unit]->rx_queue;
+
+ while(IF_QEMPTY(iqp) && (rbch_softc[unit].sc_devstate & ST_ISOPEN))
+ {
+ s = splimp();
+ rbch_softc[unit].sc_devstate |= ST_RDWAITDATA;
+ splx(s);
+
+ DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, wait read data\n", unit));
+
+ if((error = tsleep((caddr_t) &isdn_linktab[unit]->rx_queue,
+ TTIPRI | PCATCH,
+ "rrbch", 0 )) != 0)
+ {
+ DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, error %d tsleep read\n", unit, error));
+ rbch_softc[unit].sc_devstate &= ~ST_RDWAITDATA;
+ return(error);
+ }
+ }
+ }
+
+ s = splimp();
+
+ IF_DEQUEUE(iqp, m);
+
+ DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, read %d bytes\n", unit, m->m_len));
+
+ if(m && m->m_len)
+ {
+ error = uiomove(m->m_data, m->m_len, uio);
+ }
+ else
+ {
+ DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, error %d uiomove\n", unit, error));
+ error = EIO;
+ }
+
+ if(m)
+ i4b_Bfreembuf(m);
+
+ splx(s);
+
+ return(error);
+}
+
+/*---------------------------------------------------------------------------*
+ * write to rbch device
+ *---------------------------------------------------------------------------*/
+int
+i4brbchwrite(dev_t dev, struct uio * uio, int ioflag)
+{
+ struct mbuf *m;
+ int s;
+ int error = 0;
+ int unit = minor(dev);
+
+ DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, write\n", unit));
+
+ if(!(rbch_softc[unit].sc_devstate & ST_ISOPEN))
+ {
+ DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, write while not open\n", unit));
+ return(EIO);
+ }
+
+ if((rbch_softc[unit].sc_devstate & ST_NOBLOCK)) {
+ if(!(rbch_softc[unit].sc_devstate & ST_CONNECTED))
+ return(EWOULDBLOCK);
+ if(IF_QFULL(isdn_linktab[unit]->tx_queue) && (rbch_softc[unit].sc_devstate & ST_ISOPEN))
+ return(EWOULDBLOCK);
+ } else {
+ while(!(rbch_softc[unit].sc_devstate & ST_CONNECTED))
+ {
+ DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, write wait init\n", unit));
+
+ error = tsleep((caddr_t) &rbch_softc[unit],
+ TTIPRI | PCATCH,
+ "wrrbch", 0 );
+ if(error == ERESTART)
+ return (ERESTART);
+ else if(error == EINTR) {
+ printf("\n ========= i4brbchwrite, EINTR during wait init ======== \n");
+ return(EINTR);
+ } else if(error) {
+ DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, error %d tsleep init\n", unit, error));
+ return(error);
+ }
+/*XXX*/ tsleep((caddr_t) &rbch_softc[unit], TTIPRI | PCATCH, "xrbch", (hz*1));
+ }
+
+ while(IF_QFULL(isdn_linktab[unit]->tx_queue) && (rbch_softc[unit].sc_devstate & ST_ISOPEN))
+ {
+ s = splimp();
+ rbch_softc[unit].sc_devstate |= ST_WRWAITEMPTY;
+ splx(s);
+
+ DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, write queue full\n", unit));
+
+ if ((error = tsleep((caddr_t) &isdn_linktab[unit]->tx_queue,
+ TTIPRI | PCATCH,
+ "wrbch", 0)) != 0) {
+ rbch_softc[unit].sc_devstate &= ~ST_WRWAITEMPTY;
+ if(error == ERESTART) {
+ return(ERESTART);
+ } else if(error == EINTR) {
+ printf("\n ========= i4brbchwrite, EINTR during wait write ======== \n");
+ return(error);
+ } else if(error) {
+ DBGL4(L4_RBCHDBG, "i4brbchwrite",
+ ("unit %d, error %d tsleep write\n", unit, error));
+ return(error);
+ }
+ }
+ }
+ }
+
+ s = splimp();
+
+ if(!(rbch_softc[unit].sc_devstate & ST_ISOPEN))
+ {
+ DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, not open anymore\n", unit));
+ splx(s);
+ return(EIO);
+ }
+
+ if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
+ {
+ m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid);
+
+ DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, write %d bytes\n", unit, m->m_len));
+
+ error = uiomove(m->m_data, m->m_len, uio);
+
+ IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
+
+ (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
+ }
+
+ splx(s);
+
+ return(error);
+}
+
+PDEVSTATIC int
+i4brbchioctl(dev_t dev, IOCTL_CMD_T cmd, caddr_t data, int flag, struct proc* p) {
+ int error = 0;
+ int unit = minor(dev);
+
+ switch(cmd)
+ {
+#if 0
+ case I4B_RBCH_DIALOUT:
+if(bootverbose)printf("EE-rbch%d: attempting dialout (ioctl)\n", unit);
+ i4b_l4_dialout(BDRV_RBCH, unit);
+ break;
+#endif
+
+ case FIOASYNC: /* Set async mode */
+ if (*(int *)data) {
+if(bootverbose)printf("EE-rbch%d: setting async mode\n", unit);
+ } else {
+if(bootverbose)printf("EE-rbch%d: clearing async mode\n", unit);
+ }
+ break;
+ case FIONBIO:
+ if (*(int *)data) {
+if(bootverbose)printf("EE-rbch%d: setting non-blocking mode\n", unit);
+ rbch_softc[unit].sc_devstate |= ST_NOBLOCK;
+ } else {
+if(bootverbose)printf("EE-rbch%d: clearing non-blocking mode\n", unit);
+ rbch_softc[unit].sc_devstate &= ~ST_NOBLOCK;
+ }
+ break;
+ case TIOCCDTR: /* Clear DTR */
+ if(rbch_softc[unit].sc_devstate & ST_CONNECTED) {
+if(bootverbose)printf("EE-rbch%d: disconnecting for DTR down\n", unit);
+ i4b_l4_disconnect_ind(rbch_softc[unit].cd);
+ }
+ break;
+ case TIOCSDTR: /* Set DTR */
+if(bootverbose)printf("EE-rbch%d: attempting dialout (DTR)\n", unit);
+ i4b_l4_dialout(BDRV_RBCH, unit);
+ break;
+ case TIOCSETA: /* Set termios struct */
+ break;
+ case TIOCGETA: /* Get termios struct */
+ *(struct termios *)data = rbch_softc[unit].it_in;
+ break;
+ case TIOCMGET:
+ *(int *)data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR;
+ if (rbch_softc[unit].sc_devstate & ST_CONNECTED)
+ *(int *)data |= TIOCM_CD;
+ break;
+ default: /* Unknown stuff */
+ printf("\n ========= i4brbch%d - ioctl, unknown cmd %lx ==================== \n",
+ unit,
+ (u_long)cmd);
+ error = EINVAL;
+ break;
+ }
+ return(error);
+}
+
+/*---------------------------------------------------------------------------*
+ * device driver poll
+ *---------------------------------------------------------------------------*/
+#if (defined(__FreeBSD_version) && __FreeBSD_version >= 300001) || !defined(__FreeBSD__)
+
+PDEVSTATIC int
+i4brbchpoll(dev_t dev, int events, struct proc *p)
+{
+ int revents = 0; /* Events we found */
+ int s;
+ int unit = minor(dev);
+
+ /* We can't check for anything but IN or OUT */
+
+ if((events & (POLLIN|POLLOUT)) == 0)
+ return(POLLNVAL);
+
+ s = splhigh();
+
+ if(!(rbch_softc[unit].sc_devstate & ST_ISOPEN))
+ {
+ splx(s);
+ return(POLLNVAL);
+ }
+
+ /*
+ * Writes are OK if we are connected and the
+ * transmit queue can take them
+ */
+
+ if((events & POLLOUT) &&
+ (rbch_softc[unit].sc_devstate & ST_CONNECTED) &&
+ !IF_QFULL(isdn_linktab[unit]->tx_queue))
+ {
+ revents |= POLLOUT;
+ }
+
+ /* ... while reads are OK if we have any data */
+
+ if((events & POLLIN) &&
+ (rbch_softc[unit].sc_devstate & ST_CONNECTED))
+ {
+ struct ifqueue *iqp;
+
+ if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
+ iqp = &rbch_softc[unit].sc_hdlcq;
+ else
+ iqp = isdn_linktab[unit]->rx_queue;
+
+ if(!IF_QEMPTY(iqp))
+ revents |= POLLIN;
+ }
+
+ if(revents == 0)
+ selrecord(p, &rbch_softc[unit].selp);
+
+ splx(s);
+ return(revents);
+}
+
+#else
+
+/*---------------------------------------------------------------------------*
+ * device driver select
+ *---------------------------------------------------------------------------*/
+static int
+i4brbchselect(dev_t dev, int rw, struct proc *p)
+{
+ int unit = minor(dev);
+ int s;
+
+ s = splhigh();
+
+ if(!(rbch_softc[unit].sc_devstate & ST_ISOPEN))
+ {
+ splx(s);
+ DBGL4(L4_RBCHDBG, "i4brbchselect", ("unit %d, not open anymore\n", unit));
+ return(1);
+ }
+
+ if(rbch_softc[unit].sc_devstate & ST_CONNECTED)
+ {
+ struct ifqueue *iqp;
+
+ switch(rw)
+ {
+ case FREAD:
+ if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
+ iqp = &rbch_softc[unit].sc_hdlcq;
+ else
+ iqp = isdn_linktab[unit]->rx_queue;
+
+ if(!IF_QEMPTY(iqp))
+ return(1);
+ break;
+
+ case FWRITE:
+ if(!IF_QFULL(isdn_linktab[unit]->rx_queue))
+ return(1);
+ break;
+
+ default:
+ return 0;
+ }
+ }
+ selrecord(p, &rbch_softc[unit].selp);
+ return(0);
+}
+
+#endif /* defined(__FreeBSD_version) && __FreeBSD_version >= 300001 */
+
+/*===========================================================================*
+ * ISDN INTERFACE ROUTINES
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from L4 handler at connect time
+ *---------------------------------------------------------------------------*/
+static void
+rbch_connect(int unit, void *cdp)
+{
+ call_desc_t *cd = (call_desc_t *)cdp;
+
+ rbch_softc[unit].sc_bprot = cd->bprot;
+
+ if(!(rbch_softc[unit].sc_devstate & ST_CONNECTED))
+ {
+ DBGL4(L4_RBCHDBG, "rbch_connect", ("unit %d, wakeup\n", unit));
+ rbch_softc[unit].sc_devstate |= ST_CONNECTED;
+ rbch_softc[unit].cd = cdp;
+ wakeup((caddr_t) &rbch_softc[unit]);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from L4 handler at disconnect time
+ *---------------------------------------------------------------------------*/
+static void
+rbch_disconnect(int unit, void *cdp)
+{
+ /* call_desc_t *cd = (call_desc_t *)cdp; */
+
+ DBGL4(L4_RBCHDBG, "rbch_disconnect", ("unit %d, deinit\n", unit));
+ rbch_softc[unit].sc_devstate &= ~ST_CONNECTED;
+ rbch_softc[unit].cd = NULL;
+}
+
+/*---------------------------------------------------------------------------*
+ * feedback from daemon in case of dial problems
+ *---------------------------------------------------------------------------*/
+static void
+rbch_dialresponse(int unit, int status)
+{
+}
+
+/*---------------------------------------------------------------------------*
+ * interface up/down
+ *---------------------------------------------------------------------------*/
+static void
+rbch_updown(int unit, int updown)
+{
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * when a new frame (mbuf) has been received and is to be put on
+ * the rx queue.
+ *---------------------------------------------------------------------------*/
+static void
+rbch_rx_data_rdy(int unit)
+{
+ if(rbch_softc[unit].sc_bprot == BPROT_RHDLC)
+ {
+ register struct mbuf *m;
+
+ if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
+ return;
+
+ m->m_pkthdr.len = m->m_len;
+
+ if(IF_QFULL(&(rbch_softc[unit].sc_hdlcq)))
+ {
+ DBGL4(L4_RBCHDBG, "rbch_rx_data_rdy", ("unit %d: hdlc rx queue full!\n", unit));
+ m_freem(m);
+ }
+ else
+ {
+ IF_ENQUEUE(&(rbch_softc[unit].sc_hdlcq), m);
+ }
+ }
+
+ if(rbch_softc[unit].sc_devstate & ST_RDWAITDATA)
+ {
+ DBGL4(L4_RBCHDBG, "rbch_rx_data_rdy", ("unit %d, wakeup\n", unit));
+ rbch_softc[unit].sc_devstate &= ~ST_RDWAITDATA;
+ wakeup((caddr_t) &isdn_linktab[unit]->rx_queue);
+ }
+ else
+ {
+ DBGL4(L4_RBCHDBG, "rbch_rx_data_rdy", ("unit %d, NO wakeup\n", unit));
+ }
+ selwakeup(&rbch_softc[unit].selp);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * when the last frame has been sent out and there is no
+ * further frame (mbuf) in the tx queue.
+ *---------------------------------------------------------------------------*/
+static void
+rbch_tx_queue_empty(int unit)
+{
+ if(rbch_softc[unit].sc_devstate & ST_WRWAITEMPTY)
+ {
+ DBGL4(L4_RBCHDBG, "rbch_tx_queue_empty", ("unit %d, wakeup\n", unit));
+ rbch_softc[unit].sc_devstate &= ~ST_WRWAITEMPTY;
+ wakeup((caddr_t) &isdn_linktab[unit]->tx_queue);
+ }
+ else
+ {
+ DBGL4(L4_RBCHDBG, "rbch_tx_queue_empty", ("unit %d, NO wakeup\n", unit));
+ }
+ selwakeup(&rbch_softc[unit].selp);
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * each time a packet is received or transmitted
+ *---------------------------------------------------------------------------*/
+static void
+rbch_activity(int unit, int rxtx)
+{
+ if (rbch_softc[unit].cd)
+ rbch_softc[unit].cd->last_active_time = SECOND;
+ selwakeup(&rbch_softc[unit].selp);
+}
+
+/*---------------------------------------------------------------------------*
+ * clear an hdlc rx queue for a rbch unit
+ *---------------------------------------------------------------------------*/
+static void
+rbch_clrq(int unit)
+{
+ int x;
+ struct mbuf *m;
+
+ for(;;)
+ {
+ x = splimp();
+ IF_DEQUEUE(&rbch_softc[unit].sc_hdlcq, m);
+ splx(x);
+ if(m)
+ m_freem(m);
+ else
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * return this drivers linktab address
+ *---------------------------------------------------------------------------*/
+drvr_link_t *
+rbch_ret_linktab(int unit)
+{
+ rbch_init_linktab(unit);
+ return(&rbch_drvr_linktab[unit]);
+}
+
+/*---------------------------------------------------------------------------*
+ * setup the isdn_linktab for this driver
+ *---------------------------------------------------------------------------*/
+void
+rbch_set_linktab(int unit, isdn_link_t *ilt)
+{
+ isdn_linktab[unit] = ilt;
+}
+
+/*---------------------------------------------------------------------------*
+ * initialize this drivers linktab
+ *---------------------------------------------------------------------------*/
+static void
+rbch_init_linktab(int unit)
+{
+ rbch_drvr_linktab[unit].unit = unit;
+ rbch_drvr_linktab[unit].bch_rx_data_ready = rbch_rx_data_rdy;
+ rbch_drvr_linktab[unit].bch_tx_queue_empty = rbch_tx_queue_empty;
+ rbch_drvr_linktab[unit].bch_activity = rbch_activity;
+ rbch_drvr_linktab[unit].line_connected = rbch_connect;
+ rbch_drvr_linktab[unit].line_disconnected = rbch_disconnect;
+ rbch_drvr_linktab[unit].dial_response = rbch_dialresponse;
+ rbch_drvr_linktab[unit].updown_ind = rbch_updown;
+}
+
+/*===========================================================================*/
+
+#endif /* NI4BRBCH > 0 */
diff --git a/sys/i4b/driver/i4b_tel.c b/sys/i4b/driver/i4b_tel.c
new file mode 100644
index 0000000..81b38a6
--- /dev/null
+++ b/sys/i4b/driver/i4b_tel.c
@@ -0,0 +1,713 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_tel.c - device driver for ISDN telephony
+ * --------------------------------------------
+ *
+ * $Id: i4b_tel.c,v 1.18 1998/12/14 10:31:53 hm Exp $
+ *
+ * last edit-date: [Mon Dec 14 11:32:06 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "i4btel.h"
+
+#if NI4BTEL > 0
+
+#undef I4BTELDEBUG
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+#include <sys/ioccom.h>
+#else
+#include <sys/ioctl.h>
+#endif
+
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+
+#ifdef __FreeBSD__
+#include "opt_devfs.h"
+#endif
+
+#ifdef DEVFS
+#include <sys/devfsext.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_tel_ioctl.h>
+#else
+#include <i4b/i4b_ioctl.h>
+#include <i4b/i4b_tel_ioctl.h>
+#endif
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_l3l4.h>
+
+typedef struct {
+ drvr_link_t drvr_linktab; /* driver linktab */
+ isdn_link_t *isdn_linktab; /* isdn linktab */
+ int devstate; /* state of this unit */
+#define ST_IDLE 0x00 /* idle */
+#define ST_CONNECTED 0x01 /* isdn connected state */
+#define ST_ISOPEN 0x02 /* userland opened */
+#define ST_RDWAITDATA 0x04 /* userland read waiting */
+#define ST_WRWAITEMPTY 0x08 /* userland write waiting */
+ int audiofmt; /* audio format conversion */
+ call_desc_t *cdp; /* call descriptor pointer */
+#ifdef DEVFS
+ void *devfs_token; /* token for DEVFS */
+#endif
+} tel_sc_t;
+
+static tel_sc_t tel_sc[NI4BTEL];
+
+/* forward decl */
+
+static void tel_rx_data_rdy(int unit);
+static void tel_tx_queue_empty(int unit);
+static void tel_init_linktab(int unit);
+static void tel_connect(int unit, void *cdp);
+static void tel_disconnect(int unit, void *cdp);
+
+static unsigned char alaw_ulaw[];
+static unsigned char ulaw_alaw[];
+
+#ifndef __FreeBSD__
+#define PDEVSTATIC /* - not static - */
+PDEVSTATIC void i4btelattach __P((void));
+PDEVSTATIC int i4btelioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+int i4btelopen __P((dev_t dev, int flag, int fmt, struct proc *p));
+int i4btelclose __P((dev_t dev, int flag, int fmt, struct proc *p));
+int i4btelread __P((dev_t dev, struct uio *uio, int ioflag));
+int i4btelwrite __P((dev_t dev, struct uio * uio, int ioflag));
+#endif
+#if BSD > 199306 && defined(__FreeBSD__)
+#define PDEVSTATIC static
+PDEVSTATIC d_open_t i4btelopen;
+PDEVSTATIC d_close_t i4btelclose;
+PDEVSTATIC d_read_t i4btelread;
+PDEVSTATIC d_read_t i4btelwrite;
+PDEVSTATIC d_ioctl_t i4btelioctl;
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+PDEVSTATIC d_poll_t i4btelpoll;
+#endif
+
+#define CDEV_MAJOR 56
+static struct cdevsw i4btel_cdevsw = {
+ i4btelopen, i4btelclose, i4btelread, i4btelwrite,
+ i4btelioctl, nostop, noreset, nodevtotty,
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ i4btelpoll, nommap, NULL, "i4btel", NULL, -1
+#else
+ noselect, nommap, NULL, "i4btel", NULL, -1
+#endif
+};
+
+PDEVSTATIC void i4btelinit(void *unused);
+
+PDEVSTATIC void i4btelattach(void *);
+PSEUDO_SET(i4btelattach, i4b_tel);
+
+/*===========================================================================*
+ * DEVICE DRIVER ROUTINES
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * initialization at kernel load time
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC void
+i4btelinit(void *unused)
+{
+ dev_t dev;
+
+ dev = makedev(CDEV_MAJOR, 0);
+
+ cdevsw_add(&dev, &i4btel_cdevsw, NULL);
+}
+
+SYSINIT(i4bteldev, SI_SUB_DRIVERS,
+ SI_ORDER_MIDDLE+CDEV_MAJOR, &i4btelinit, NULL);
+
+#endif /* BSD > 199306 && defined(__FreeBSD__) */
+
+/*---------------------------------------------------------------------------*
+ * interface attach routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC void
+#ifdef __FreeBSD__
+i4btelattach(void *dummy)
+#else
+i4btelattach()
+#endif
+{
+ int i;
+
+#ifndef HACK_NO_PSEUDO_ATTACH_MSG
+ printf("i4btel: %d ISDN telephony interface device(s) attached\n", NI4BTEL);
+#endif
+
+ for(i=0; i < NI4BTEL; i++)
+ {
+ tel_sc[i].devstate = ST_IDLE;
+ tel_sc[i].audiofmt = CVT_NONE;
+ tel_init_linktab(i);
+#ifdef DEVFS
+ tel_sc[i].devfs_token
+ = devfs_add_devswf(&i4btel_cdevsw, i, DV_CHR,
+ UID_ROOT, GID_WHEEL, 0600,
+ "i4btel%d", i);
+#endif
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * open tel device
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4btelopen(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int unit = minor(dev);
+ tel_sc_t *sc;
+
+ if(unit > NI4BTEL)
+ return(ENXIO);
+
+ sc = &tel_sc[unit];
+
+ if(!(sc->devstate & ST_CONNECTED))
+ return(EIO);
+
+ if(sc->devstate & ST_ISOPEN)
+ return(EBUSY);
+
+ sc->devstate |= ST_ISOPEN;
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * close tel device
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4btelclose(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int unit = minor(dev);
+ tel_sc_t *sc;
+ int error = 0;
+
+ if(unit > NI4BTEL)
+ return(ENXIO);
+
+ sc = &tel_sc[unit];
+
+ if(sc->isdn_linktab != NULL && sc->isdn_linktab->tx_queue != NULL)
+ {
+ while(!(IF_QEMPTY(sc->isdn_linktab->tx_queue)))
+ {
+ sc->devstate |= ST_WRWAITEMPTY;
+
+ if((error = tsleep((caddr_t) &sc->isdn_linktab->tx_queue,
+ TTIPRI | PCATCH, "wtcl", 0)) != 0)
+ {
+ break;
+ }
+ }
+ sc->devstate &= ~ST_WRWAITEMPTY;
+ }
+ sc->devstate &= ~ST_ISOPEN;
+ return(error);
+}
+
+/*---------------------------------------------------------------------------*
+ * i4btelioctl - device driver ioctl routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300003
+i4btelioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+#else
+i4btelioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+#endif
+{
+ int error = 0;
+ struct mbuf *m;
+ int s;
+ tel_sc_t *sc = &tel_sc[minor(dev)];
+
+ switch(cmd)
+ {
+ case I4B_TEL_GETAUDIOFMT:
+ *(int *)data = sc->audiofmt;
+ break;
+
+ case I4B_TEL_SETAUDIOFMT:
+ sc->audiofmt = *(int *)data;
+ break;
+
+ case I4B_TEL_EMPTYINPUTQUEUE:
+ s = splimp();
+ while((sc->devstate & ST_CONNECTED) &&
+ (sc->devstate & ST_ISOPEN) &&
+ !IF_QEMPTY(sc->isdn_linktab->rx_queue))
+ {
+ IF_DEQUEUE(sc->isdn_linktab->rx_queue, m);
+ if(m)
+ i4b_Bfreembuf(m);
+ }
+ splx(s);
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return(error);
+}
+
+/*---------------------------------------------------------------------------*
+ * read from tel device
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4btelread(dev_t dev, struct uio *uio, int ioflag)
+{
+ struct mbuf *m;
+ int s;
+ int error = 0;
+ tel_sc_t *sc = &tel_sc[minor(dev)];
+
+ if(!(sc->devstate & ST_CONNECTED))
+ return(EIO);
+
+ if(!(sc->devstate & ST_ISOPEN))
+ return(EIO);
+
+#ifdef NOTDEF
+ while(!(sc->devstate & ST_CONNECTED))
+ {
+ if((error = tsleep((caddr_t) &sc->devstate,
+ TTIPRI | PCATCH,
+ "rrtel", 0 )) != 0)
+ {
+ return(error);
+ }
+ }
+#endif
+
+ while(IF_QEMPTY(sc->isdn_linktab->rx_queue) &&
+ (sc->devstate & ST_ISOPEN) &&
+ (sc->devstate & ST_CONNECTED))
+ {
+ sc->devstate |= ST_RDWAITDATA;
+
+ if((error = tsleep((caddr_t) &sc->isdn_linktab->rx_queue,
+ TTIPRI | PCATCH,
+ "rtel", 0 )) != 0)
+ {
+ sc->devstate &= ~ST_RDWAITDATA;
+ return(error);
+ }
+ }
+
+ if(!(sc->devstate & ST_ISOPEN))
+ {
+ return(EIO);
+ }
+
+ if(!(sc->devstate & ST_CONNECTED))
+ {
+ return(EIO);
+ }
+
+ s = splimp();
+
+ IF_DEQUEUE(sc->isdn_linktab->rx_queue, m);
+
+ if(m && m->m_len)
+ {
+ if(sc->audiofmt == CVT_ALAW2ULAW)
+ {
+ int i;
+ for(i = 0; i < m->m_len; i++)
+ m->m_data[i] = alaw_ulaw[(int)m->m_data[i]];
+ }
+ error = uiomove(m->m_data, m->m_len, uio);
+ }
+ else
+ {
+ error = EIO;
+ }
+
+ if(m)
+ i4b_Bfreembuf(m);
+
+ splx(s);
+
+ return(error);
+}
+
+/*---------------------------------------------------------------------------*
+ * write to tel device
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4btelwrite(dev_t dev, struct uio * uio, int ioflag)
+{
+ struct mbuf *m;
+ int s;
+ int error = 0;
+ tel_sc_t *sc = &tel_sc[minor(dev)];
+
+ if(!(sc->devstate & ST_CONNECTED))
+ return(EIO);
+
+ if(!(sc->devstate & ST_ISOPEN))
+ {
+ return(EIO);
+ }
+
+#ifdef NOTDEF
+ while(!(sc->devstate & ST_CONNECTED))
+ {
+ if((error = tsleep((caddr_t) &sc->devstate,
+ TTIPRI | PCATCH,
+ "wrtel", 0 )) != 0)
+ {
+ return(error);
+ }
+
+ /*
+ * XXX the originations B channel gets much earlier
+ * switched thru than the destinations B channel, so
+ * if the origination starts to send at once, some
+ * 200 bytes (at my site) or so get lost, so i delay
+ * a bit before sending. (-hm)
+ */
+
+ tsleep((caddr_t) &sc->devstate, TTIPRI | PCATCH, "xtel", (hz*1));
+ }
+#endif
+
+ while((IF_QFULL(sc->isdn_linktab->tx_queue)) &&
+ (sc->devstate & ST_ISOPEN))
+ {
+ sc->devstate |= ST_WRWAITEMPTY;
+
+ if((error = tsleep((caddr_t) &sc->isdn_linktab->tx_queue,
+ TTIPRI | PCATCH, "wtel", 0)) != 0)
+ {
+ sc->devstate &= ~ST_WRWAITEMPTY;
+ return(error);
+ }
+ }
+
+ if(!(sc->devstate & ST_ISOPEN))
+ {
+ return(EIO);
+ }
+
+ if(!(sc->devstate & ST_CONNECTED))
+ {
+ return(EIO);
+ }
+
+ s = splimp();
+
+ if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL)
+ {
+ m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid);
+
+ error = uiomove(m->m_data, m->m_len, uio);
+
+ if(sc->audiofmt == CVT_ALAW2ULAW)
+ {
+ int i;
+ for(i = 0; i < m->m_len; i++)
+ m->m_data[i] = ulaw_alaw[(int)m->m_data[i]];
+ }
+
+ IF_ENQUEUE(sc->isdn_linktab->tx_queue, m);
+
+ (*sc->isdn_linktab->bch_tx_start)(sc->isdn_linktab->unit, sc->isdn_linktab->channel);
+ }
+
+ splx(s);
+
+ return(error);
+}
+
+/*---------------------------------------------------------------------------*
+ * poll
+ *---------------------------------------------------------------------------*/
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+PDEVSTATIC int
+i4btelpoll (dev_t dev, int events, struct proc *p)
+{
+ return (ENODEV);
+}
+#endif
+
+/*===========================================================================*
+ * ISDN INTERFACE ROUTINES
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+* this routine is called from L4 handler at connect time
+ *---------------------------------------------------------------------------*/
+static void
+tel_connect(int unit, void *cdp)
+{
+ tel_sc_t *sc = &tel_sc[unit];
+
+ sc->cdp = (call_desc_t *)cdp;
+
+#ifdef NOTDEF
+ if(!(sc->devstate & ST_CONNECTED))
+ {
+ sc->devstate |= ST_CONNECTED;
+ wakeup((caddr_t) &sc->devstate);
+ }
+#else
+ sc->devstate |= ST_CONNECTED;
+#endif
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from L4 handler at disconnect time
+ *---------------------------------------------------------------------------*/
+static void
+tel_disconnect(int unit, void *cdp)
+{
+/* call_desc_t *cd = (call_desc_t *)cdp; */
+
+ tel_sc_t *sc = &tel_sc[unit];
+
+ sc->devstate &= ~ST_CONNECTED;
+
+ if(sc->devstate & ST_RDWAITDATA)
+ {
+ sc->devstate &= ~ST_RDWAITDATA;
+ wakeup((caddr_t) &sc->isdn_linktab->rx_queue);
+ }
+
+ if(sc->devstate & ST_WRWAITEMPTY)
+ {
+ sc->devstate &= ~ST_WRWAITEMPTY;
+ wakeup((caddr_t) &sc->isdn_linktab->tx_queue);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * feedback from daemon in case of dial problems
+ *---------------------------------------------------------------------------*/
+static void
+tel_dialresponse(int unit, int status)
+{
+}
+
+/*---------------------------------------------------------------------------*
+ * interface up/down
+ *---------------------------------------------------------------------------*/
+static void
+tel_updown(int unit, int updown)
+{
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * when a new frame (mbuf) has been received and was put on
+ * the rx queue.
+ *---------------------------------------------------------------------------*/
+static void
+tel_rx_data_rdy(int unit)
+{
+ tel_sc_t *sc = &tel_sc[unit];
+
+ if(sc->devstate & ST_RDWAITDATA)
+ {
+ sc->devstate &= ~ST_RDWAITDATA;
+ wakeup((caddr_t) &sc->isdn_linktab->rx_queue);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * when the last frame has been sent out and there is no
+ * further frame (mbuf) in the tx queue.
+ *---------------------------------------------------------------------------*/
+static void
+tel_tx_queue_empty(int unit)
+{
+ tel_sc_t *sc = &tel_sc[unit];
+
+ if(sc->devstate & ST_WRWAITEMPTY)
+ {
+ sc->devstate &= ~ST_WRWAITEMPTY;
+ wakeup((caddr_t) &sc->isdn_linktab->tx_queue);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * this routine is called from the HSCX interrupt handler
+ * each time a packet is received or transmitted.
+ *---------------------------------------------------------------------------*/
+static void
+tel_activity(int unit, int rxtx)
+{
+ tel_sc[unit].cdp->last_active_time = SECOND;
+}
+
+/*---------------------------------------------------------------------------*
+ * return this drivers linktab address
+ *---------------------------------------------------------------------------*/
+drvr_link_t *
+tel_ret_linktab(int unit)
+{
+ tel_sc_t *sc = &tel_sc[unit];
+
+ tel_init_linktab(unit);
+ return(&sc->drvr_linktab);
+}
+
+/*---------------------------------------------------------------------------*
+ * setup the isdn_linktab for this driver
+ *---------------------------------------------------------------------------*/
+void
+tel_set_linktab(int unit, isdn_link_t *ilt)
+{
+ tel_sc_t *sc = &tel_sc[unit];
+ sc->isdn_linktab = ilt;
+}
+
+/*---------------------------------------------------------------------------*
+ * initialize this drivers linktab
+ *---------------------------------------------------------------------------*/
+static void
+tel_init_linktab(int unit)
+{
+ tel_sc_t *sc = &tel_sc[unit];
+
+ sc->drvr_linktab.unit = unit;
+ sc->drvr_linktab.bch_rx_data_ready = tel_rx_data_rdy;
+ sc->drvr_linktab.bch_tx_queue_empty = tel_tx_queue_empty;
+ sc->drvr_linktab.bch_activity = tel_activity;
+ sc->drvr_linktab.line_connected = tel_connect;
+ sc->drvr_linktab.line_disconnected = tel_disconnect;
+ sc->drvr_linktab.dial_response = tel_dialresponse;
+ sc->drvr_linktab.updown_ind = tel_updown;
+}
+
+/*===========================================================================*
+ * AUDIO FORMAT CONVERSION
+ *===========================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * A-law to mu-law conversion
+ *---------------------------------------------------------------------------*/
+static unsigned char alaw_ulaw[] = {
+ 0x002a, 0x00a9, 0x005f, 0x00e3, 0x001f, 0x009f, 0x0048, 0x00c8,
+ 0x0039, 0x00b9, 0x006f, 0x00f7, 0x001f, 0x009f, 0x0055, 0x00d7,
+ 0x0022, 0x00a1, 0x005b, 0x00dd, 0x001f, 0x009f, 0x0040, 0x00c0,
+ 0x0031, 0x00b1, 0x0067, 0x00eb, 0x001f, 0x009f, 0x004e, 0x00cf,
+ 0x002e, 0x00ad, 0x0063, 0x00e7, 0x001f, 0x009f, 0x004c, 0x00cc,
+ 0x003d, 0x00bd, 0x0077, 0x00ff, 0x001f, 0x009f, 0x0059, 0x00db,
+ 0x0026, 0x00a5, 0x005d, 0x00df, 0x001f, 0x009f, 0x0044, 0x00c4,
+ 0x0035, 0x00b5, 0x006b, 0x00ef, 0x001f, 0x009f, 0x0051, 0x00d3,
+ 0x0028, 0x00a7, 0x005f, 0x00e3, 0x001f, 0x009f, 0x0046, 0x00c6,
+ 0x0037, 0x00b7, 0x006f, 0x00f7, 0x001f, 0x009f, 0x0053, 0x00d5,
+ 0x0020, 0x009f, 0x005b, 0x00dd, 0x001f, 0x009f, 0x003f, 0x00bf,
+ 0x002f, 0x00af, 0x0067, 0x00eb, 0x001f, 0x009f, 0x004d, 0x00ce,
+ 0x002c, 0x00ab, 0x0063, 0x00e7, 0x001f, 0x009f, 0x004a, 0x00ca,
+ 0x003b, 0x00bb, 0x0077, 0x00ff, 0x001f, 0x009f, 0x0057, 0x00d9,
+ 0x0024, 0x00a3, 0x005d, 0x00df, 0x001f, 0x009f, 0x0042, 0x00c2,
+ 0x0033, 0x00b3, 0x006b, 0x00ef, 0x001f, 0x009f, 0x004f, 0x00d1,
+ 0x002b, 0x00aa, 0x0063, 0x00e3, 0x001f, 0x009f, 0x0049, 0x00c9,
+ 0x003a, 0x00ba, 0x0077, 0x00f7, 0x001f, 0x009f, 0x0057, 0x00d7,
+ 0x0023, 0x00a2, 0x005d, 0x00dd, 0x001f, 0x009f, 0x0041, 0x00c1,
+ 0x0032, 0x00b2, 0x006b, 0x00eb, 0x001f, 0x009f, 0x004f, 0x00cf,
+ 0x002f, 0x00ae, 0x0067, 0x00e7, 0x001f, 0x009f, 0x004d, 0x00cd,
+ 0x003e, 0x00be, 0x00ff, 0x00ff, 0x001f, 0x009f, 0x005b, 0x00db,
+ 0x0027, 0x00a6, 0x005f, 0x00df, 0x001f, 0x009f, 0x0045, 0x00c5,
+ 0x0036, 0x00b6, 0x006f, 0x00ef, 0x001f, 0x009f, 0x0053, 0x00d3,
+ 0x0029, 0x00a8, 0x005f, 0x00e3, 0x001f, 0x009f, 0x0047, 0x00c7,
+ 0x0038, 0x00b8, 0x006f, 0x00f7, 0x001f, 0x009f, 0x0055, 0x00d5,
+ 0x0021, 0x00a0, 0x005b, 0x00dd, 0x001f, 0x009f, 0x003f, 0x00bf,
+ 0x0030, 0x00b0, 0x0067, 0x00eb, 0x001f, 0x009f, 0x004e, 0x00ce,
+ 0x002d, 0x00ac, 0x0063, 0x00e7, 0x001f, 0x009f, 0x004b, 0x00cb,
+ 0x003c, 0x00bc, 0x0077, 0x00ff, 0x001f, 0x009f, 0x0059, 0x00d9,
+ 0x0025, 0x00a4, 0x005d, 0x00df, 0x001f, 0x009f, 0x0043, 0x00c3,
+ 0x0034, 0x00b4, 0x006b, 0x00ef, 0x001f, 0x009f, 0x0051, 0x00d1
+};
+
+/*---------------------------------------------------------------------------*
+ * mu-law to A-law conversion
+ *---------------------------------------------------------------------------*/
+static unsigned char ulaw_alaw[] = {
+ 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc,
+ 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc,
+ 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc,
+ 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00ac,
+ 0x0050, 0x00d0, 0x0010, 0x0090, 0x0070, 0x00f0, 0x0030, 0x00b0,
+ 0x0040, 0x00c0, 0x0000, 0x0080, 0x0060, 0x00e0, 0x0020, 0x00a0,
+ 0x00d8, 0x0018, 0x0098, 0x0078, 0x00f8, 0x0038, 0x00b8, 0x0048,
+ 0x00c8, 0x0008, 0x0088, 0x0068, 0x00e8, 0x0028, 0x00a8, 0x00d6,
+ 0x0096, 0x0076, 0x00f6, 0x0036, 0x00b6, 0x0046, 0x00c6, 0x0006,
+ 0x0086, 0x0066, 0x00e6, 0x0026, 0x00a6, 0x00de, 0x009e, 0x00fe,
+ 0x00fe, 0x00be, 0x00be, 0x00ce, 0x00ce, 0x008e, 0x008e, 0x00ee,
+ 0x00ee, 0x00d2, 0x00d2, 0x00f2, 0x00f2, 0x00c2, 0x00c2, 0x00e2,
+ 0x00e2, 0x00e2, 0x00da, 0x00da, 0x00da, 0x00da, 0x00fa, 0x00fa,
+ 0x00fa, 0x00fa, 0x00ca, 0x00ca, 0x00ca, 0x00ca, 0x00ea, 0x00ea,
+ 0x00ea, 0x00ea, 0x00ea, 0x00ea, 0x00eb, 0x00eb, 0x00eb, 0x00eb,
+ 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb,
+ 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd,
+ 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd,
+ 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd,
+ 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd,
+ 0x00d1, 0x0011, 0x0091, 0x0071, 0x00f1, 0x0031, 0x00b1, 0x0041,
+ 0x00c1, 0x0001, 0x0081, 0x0061, 0x00e1, 0x0021, 0x00a1, 0x0059,
+ 0x00d9, 0x0019, 0x0099, 0x0079, 0x00f9, 0x0039, 0x00b9, 0x0049,
+ 0x00c9, 0x0009, 0x0089, 0x0069, 0x00e9, 0x0029, 0x00a9, 0x0057,
+ 0x0017, 0x0097, 0x0077, 0x00f7, 0x0037, 0x00b7, 0x0047, 0x00c7,
+ 0x0007, 0x0087, 0x0067, 0x00e7, 0x0027, 0x00a7, 0x00df, 0x009f,
+ 0x009f, 0x00ff, 0x00ff, 0x00bf, 0x00bf, 0x00cf, 0x00cf, 0x008f,
+ 0x008f, 0x00ef, 0x00ef, 0x00af, 0x00af, 0x00d3, 0x00d3, 0x00f3,
+ 0x00f3, 0x00f3, 0x00c3, 0x00c3, 0x00c3, 0x00c3, 0x00e3, 0x00e3,
+ 0x00e3, 0x00e3, 0x00db, 0x00db, 0x00db, 0x00db, 0x00fb, 0x00fb,
+ 0x00fb, 0x00fb, 0x00fb, 0x00fb, 0x00cb, 0x00cb, 0x00cb, 0x00cb,
+ 0x00cb, 0x00cb, 0x00cb, 0x00cb, 0x00eb, 0x00eb, 0x00eb, 0x00eb
+};
+
+/*===========================================================================*/
+
+#endif /* NI4BTEL > 0 */
diff --git a/sys/i4b/driver/i4b_trace.c b/sys/i4b/driver/i4b_trace.c
new file mode 100644
index 0000000..f64e35d
--- /dev/null
+++ b/sys/i4b/driver/i4b_trace.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4btrc - device driver for trace data read device
+ * ---------------------------------------------------
+ *
+ * $Id: i4b_trace.c,v 1.14 1998/12/05 18:02:51 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:01:53 1998]
+ *
+ * NOTE: the code assumes that SPLI4B >= splimp !
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "i4btrc.h"
+
+#if NI4BTRC > 0
+
+#ifdef __FreeBSD__
+#include "isic.h" /* 'isic' is no pseudo-device on non FreeBSD -
+ * so we just can't count it at compile time,
+ * we're doing an attach-time check instead. */
+
+#if NI4BTRC < NISIC
+#error "number of trace devices != number of passive ISDN controllers !"
+#error "change number of i4btrc to be equal to number of isic devices !"
+#endif
+#endif /* __FreeBSD__ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <sys/ioccom.h>
+#else
+#include <sys/ioctl.h>
+#endif
+
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+
+#ifdef __FreeBSD__
+#include "opt_devfs.h"
+#endif
+
+#ifdef DEVFS
+#include <sys/devfsext.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <machine/i4b_trace.h>
+#include <machine/i4b_ioctl.h>
+#else
+#include <i4b/i4b_trace.h>
+#include <i4b/i4b_ioctl.h>
+#endif
+
+#ifndef __FreeBSD__
+#define memcpy(d,s,l) bcopy(s,d,l)
+#endif
+
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l3l4.h>
+
+static struct ifqueue trace_queue[NI4BTRC];
+static int device_state[NI4BTRC];
+#define ST_IDLE 0x00
+#define ST_ISOPEN 0x01
+#define ST_WAITDATA 0x02
+#ifdef DEVFS
+static void *devfs_token[NI4BTRC];
+#endif
+
+static int analyzemode = 0;
+static int rxunit = -1;
+static int txunit = -1;
+static int outunit = -1;
+
+#ifndef __FreeBSD__
+#define PDEVSTATIC /* - not static - */
+void i4btrcattach __P((void));
+int i4btrcopen __P((dev_t dev, int flag, int fmt, struct proc *p));
+int i4btrcclose __P((dev_t dev, int flag, int fmt, struct proc *p));
+int i4btrcread __P((dev_t dev, struct uio * uio, int ioflag));
+int i4btrcioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+#endif
+
+#if BSD > 199306 && defined(__FreeBSD__)
+#define PDEVSTATIC static
+static d_open_t i4btrcopen;
+static d_close_t i4btrcclose;
+static d_read_t i4btrcread;
+static d_ioctl_t i4btrcioctl;
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+static d_poll_t i4btrcpoll;
+#endif
+
+#define CDEV_MAJOR 59
+static struct cdevsw i4btrc_cdevsw = {
+ i4btrcopen, i4btrcclose, i4btrcread, nowrite,
+ i4btrcioctl, nostop, noreset, nodevtotty,
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ i4btrcpoll, nommap, NULL, "i4btrc", NULL, -1
+#else
+ noselect, nommap, NULL, "i4btrc", NULL, -1
+#endif
+};
+
+/*---------------------------------------------------------------------------*
+ * interface init routine
+ *---------------------------------------------------------------------------*/
+static
+void i4btrcinit(void *unused)
+{
+ dev_t dev;
+
+ dev = makedev(CDEV_MAJOR, 0);
+
+ cdevsw_add(&dev, &i4btrc_cdevsw, NULL);
+}
+
+SYSINIT(i4btrcdev, SI_SUB_DRIVERS,
+ SI_ORDER_MIDDLE+CDEV_MAJOR, &i4btrcinit, NULL);
+
+static void i4btrcattach(void *);
+PSEUDO_SET(i4btrcattach, i4b_trace);
+
+#endif /* BSD > 199306 && defined(__FreeBSD__) */
+
+int get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf);
+
+/*---------------------------------------------------------------------------*
+ * interface attach routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC void
+#ifdef __FreeBSD__
+i4btrcattach(void *dummy)
+#else
+i4btrcattach()
+#endif
+{
+ int i;
+
+#ifndef HACK_NO_PSEUDO_ATTACH_MSG
+ printf("i4btrc: %d ISDN trace device(s) attached\n", NI4BTRC);
+#endif
+
+ for(i=0; i < NI4BTRC; i++)
+ {
+#ifdef DEVFS
+ devfs_token[i]
+ = devfs_add_devswf(&i4btrc_cdevsw, i, DV_CHR,
+ UID_ROOT, GID_WHEEL, 0600,
+ "i4btrc%d", i);
+#endif
+ trace_queue[i].ifq_maxlen = IFQ_MAXLEN;
+ device_state[i] = ST_IDLE;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * get_trace_data_from_l1()
+ * ------------------------
+ * is called from layer 1, adds timestamp to trace data and puts
+ * it into a queue, from which it can be read from the i4btrc
+ * device. The unit number in the trace header selects the minor
+ * device's queue the data is put into.
+ *---------------------------------------------------------------------------*/
+int
+get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf)
+{
+ struct mbuf *m;
+ int x;
+ int unit;
+ int trunc = 0;
+ int totlen = len + sizeof(i4b_trace_hdr_t);
+
+ /*
+ * for telephony (or better non-HDLC HSCX mode) we get
+ * (MCLBYTE + sizeof(i4b_trace_hdr_t)) length packets
+ * to put into the queue to userland. because of this
+ * we detect this situation, strip the length to MCLBYTES
+ * max size, and infor the userland program of this fact
+ * by putting the no of truncated bytes into hdr->trunc.
+ */
+
+ if(totlen > MCLBYTES)
+ {
+ trunc = 1;
+ hdr->trunc = totlen - MCLBYTES;
+ totlen = MCLBYTES;
+ }
+ else
+ {
+ hdr->trunc = 0;
+ }
+
+ /* set length of trace record */
+
+ hdr->length = totlen;
+
+ /* check valid unit no */
+
+ if((unit = hdr->unit) > NI4BTRC)
+ {
+ printf("i4b_trace: get_trace_data_from_l1 - unit > NI4BTRC!\n");
+ return(0);
+ }
+
+ /* get mbuf */
+
+ if(!(m = i4b_Bgetmbuf(totlen)))
+ {
+ printf("i4b_trace: get_trace_data_from_l1 - i4b_getmbuf() failed!\n");
+ return(0);
+ }
+
+ /* check if we are in analyzemode */
+
+ if(analyzemode && (unit == rxunit || unit == txunit))
+ {
+ if(unit == rxunit)
+ hdr->dir = FROM_NT;
+ else
+ hdr->dir = FROM_TE;
+ unit = outunit;
+ }
+
+ if(IF_QFULL(&trace_queue[unit]))
+ {
+ struct mbuf *m1;
+
+ x = SPLI4B();
+ IF_DEQUEUE(&trace_queue[unit], m1);
+ splx(x);
+
+ i4b_Bfreembuf(m1);
+ }
+
+ /* copy trace header */
+ memcpy(m->m_data, hdr, sizeof(i4b_trace_hdr_t));
+
+ /* copy trace data */
+ if(trunc)
+ memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, totlen-sizeof(i4b_trace_hdr_t));
+ else
+ memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, len);
+
+ x = SPLI4B();
+
+ IF_ENQUEUE(&trace_queue[unit], m);
+
+ if(device_state[unit] & ST_WAITDATA)
+ {
+ device_state[unit] &= ~ST_WAITDATA;
+ wakeup((caddr_t) &trace_queue[unit]);
+ }
+
+ splx(x);
+
+ return(1);
+}
+
+/*---------------------------------------------------------------------------*
+ * open trace device
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4btrcopen(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int x;
+ int unit = minor(dev);
+
+ if(unit > NI4BTRC)
+ return(ENXIO);
+
+ if(device_state[unit] & ST_ISOPEN)
+ return(EBUSY);
+
+ if(analyzemode && (unit == outunit || unit == rxunit || unit == txunit))
+ return(EBUSY);
+
+ x = SPLI4B();
+
+ device_state[unit] = ST_ISOPEN;
+
+ splx(x);
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * close trace device
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4btrcclose(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int unit = minor(dev);
+ int i, x, cno = -1;
+
+ for(i = 0; i < nctrl; i++)
+ {
+ if(ctrl_desc[i].N_SET_TRACE)
+ {
+ cno = i;
+ break;
+ }
+ }
+
+ if(analyzemode && (unit == outunit))
+ {
+ analyzemode = 0;
+ outunit = -1;
+
+ if(cno >= 0)
+ {
+ ctrl_desc[cno].N_SET_TRACE(rxunit, TRACE_OFF);
+ ctrl_desc[cno].N_SET_TRACE(txunit, TRACE_OFF);
+ }
+ rxunit = -1;
+ txunit = -1;
+ }
+
+ if(cno >= 0)
+ {
+ ctrl_desc[cno].N_SET_TRACE(unit, TRACE_OFF);
+ }
+
+ x = SPLI4B();
+ device_state[unit] = ST_IDLE;
+ splx(x);
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * read from trace device
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4btrcread(dev_t dev, struct uio * uio, int ioflag)
+{
+ struct mbuf *m;
+ int x;
+ int error = 0;
+ int unit = minor(dev);
+
+ if(!(device_state[unit] & ST_ISOPEN))
+ return(EIO);
+
+ x = SPLI4B();
+
+ while(IF_QEMPTY(&trace_queue[unit]) && (device_state[unit] & ST_ISOPEN))
+ {
+ device_state[unit] |= ST_WAITDATA;
+
+ if((error = tsleep((caddr_t) &trace_queue[unit],
+ TTIPRI | PCATCH,
+ "bitrc", 0 )) != 0)
+ {
+ device_state[unit] &= ~ST_WAITDATA;
+ splx(x);
+ return(error);
+ }
+ }
+
+ IF_DEQUEUE(&trace_queue[unit], m);
+
+ if(m && m->m_len)
+ error = uiomove(m->m_data, m->m_len, uio);
+ else
+ error = EIO;
+
+ if(m)
+ i4b_Bfreembuf(m);
+
+ splx(x);
+
+ return(error);
+}
+
+/*---------------------------------------------------------------------------*
+ * poll device
+ *---------------------------------------------------------------------------*/
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+PDEVSTATIC int
+i4btrcpoll(dev_t dev, int events, struct proc *p)
+{
+ return(ENODEV);
+}
+#endif
+
+/*---------------------------------------------------------------------------*
+ * device driver ioctl routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+#if defined (__FreeBSD_version) && __FreeBSD_version >= 300003
+i4btrcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+#else
+i4btrcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+#endif
+{
+ int error = 0;
+ int unit = minor(dev);
+ i4b_trace_setupa_t *tsa;
+ int i, cno = -1;
+
+ /* find the first passive controller to get at the set/get function
+ pointers. Would be better if we had the controller class virtual
+ function table separate from the port registry... */
+
+ for(i=0; i < nctrl; i++)
+ {
+ if(ctrl_desc[i].N_SET_TRACE)
+ {
+ cno = i; /* one suitable controller, might not */
+ break; /* be related to the trace unit at all, but */
+ } /* has the right function pointers */
+ }
+
+ switch(cmd)
+ {
+ case I4B_TRC_GET:
+ if(cno < 0)
+ return ENOTTY;
+ *(int *)data = ctrl_desc[cno].N_GET_TRACE(unit);
+ break;
+
+ case I4B_TRC_SET:
+ if(cno < 0)
+ return ENOTTY;
+ ctrl_desc[cno].N_SET_TRACE(unit, *(int *)data);
+ break;
+
+ case I4B_TRC_SETA:
+ tsa = (i4b_trace_setupa_t *)data;
+
+ if(tsa->rxunit >= 0 && tsa->rxunit < NI4BTRC)
+ rxunit = tsa->rxunit;
+ else
+ error = EINVAL;
+
+ if(tsa->txunit >= 0 && tsa->txunit < NI4BTRC)
+ txunit = tsa->txunit;
+ else
+ error = EINVAL;
+
+ if(error)
+ {
+ outunit = -1;
+ rxunit = -1;
+ txunit = -1;
+ }
+ else
+ {
+ if(cno < 0)
+ return ENOTTY;
+
+ outunit = unit;
+ analyzemode = 1;
+ ctrl_desc[cno].N_SET_TRACE(rxunit, tsa->rxflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX));
+ ctrl_desc[cno].N_SET_TRACE(txunit, tsa->txflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX));
+ }
+ break;
+
+ case I4B_TRC_RESETA:
+ analyzemode = 0;
+ outunit = -1;
+ rxunit = -1;
+ txunit = -1;
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return(error);
+}
+
+#endif /* NI4BTRC > 0 */
OpenPOWER on IntegriCloud