summaryrefslogtreecommitdiffstats
path: root/sys/i4b/layer4
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i4b/layer4')
-rw-r--r--sys/i4b/layer4/i4b_i4bdrv.c832
-rw-r--r--sys/i4b/layer4/i4b_l4.c897
-rw-r--r--sys/i4b/layer4/i4b_l4.h69
-rw-r--r--sys/i4b/layer4/i4b_l4mgmt.c467
-rw-r--r--sys/i4b/layer4/i4b_l4timer.c110
5 files changed, 2375 insertions, 0 deletions
diff --git a/sys/i4b/layer4/i4b_i4bdrv.c b/sys/i4b/layer4/i4b_i4bdrv.c
new file mode 100644
index 0000000..0c21e8e
--- /dev/null
+++ b/sys/i4b/layer4/i4b_i4bdrv.c
@@ -0,0 +1,832 @@
+/*
+ * 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_i4bdrv.c - i4b userland interface driver
+ * --------------------------------------------
+ *
+ * $Id: i4b_i4bdrv.c,v 1.33 1998/12/12 19:44:36 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:35:02 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "i4b.h"
+#include "i4bipr.h"
+
+#if NI4B > 1
+#error "only 1 (one) i4b device possible!"
+#endif
+
+#if NI4B > 0
+
+#include <sys/param.h>
+
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/uio.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 <sys/select.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>
+#include <machine/i4b_cause.h>
+#else
+#include <i4b/i4b_debug.h>
+#include <i4b/i4b_ioctl.h>
+#include <i4b/i4b_cause.h>
+#endif
+
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_global.h>
+
+#include <i4b/layer4/i4b_l4.h>
+
+#if defined(__FreeBSD__) && (!defined(__FreeBSD_version) || __FreeBSD_version < 300001)
+/* do nothing */
+#else
+#include <sys/poll.h>
+#endif
+
+struct selinfo select_rd_info;
+
+static struct ifqueue i4b_rdqueue;
+static int openflag = 0;
+static int selflag = 0;
+static int readflag = 0;
+#ifdef DEVFS
+static void *devfs_token;
+#endif
+
+#ifndef __FreeBSD__
+#define PDEVSTATIC /* - not static - */
+PDEVSTATIC void i4battach __P((void));
+PDEVSTATIC int i4bopen __P((dev_t dev, int flag, int fmt, struct proc *p));
+PDEVSTATIC int i4bclose __P((dev_t dev, int flag, int fmt, struct proc *p));
+PDEVSTATIC int i4bread __P((dev_t dev, struct uio *uio, int ioflag));
+PDEVSTATIC int i4bioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+PDEVSTATIC int i4bpoll __P((dev_t dev, int events, struct proc *p));
+
+#if defined (__OpenBSD__)
+PDEVSTATIC int i4bselect(dev_t dev, int rw, struct proc *p);
+#endif
+
+#endif
+
+#if BSD > 199306 && defined(__FreeBSD__)
+#define PDEVSTATIC static
+
+PDEVSTATIC d_open_t i4bopen;
+PDEVSTATIC d_close_t i4bclose;
+PDEVSTATIC d_read_t i4bread;
+PDEVSTATIC d_ioctl_t i4bioctl;
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+PDEVSTATIC d_poll_t i4bpoll;
+#else
+PDEVSTATIC d_select_t i4bselect;
+#endif
+
+#define CDEV_MAJOR 60
+static struct cdevsw i4b_cdevsw =
+ { i4bopen, i4bclose, i4bread, nowrite,
+ i4bioctl, nostop, nullreset, nodevtotty,
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ i4bpoll, nommap, NULL, "i4b", NULL, -1 };
+#else
+ i4bselect, nommap, NULL, "i4b", NULL, -1 };
+#endif
+
+PDEVSTATIC void i4battach(void *);
+PSEUDO_SET(i4battach, i4b_i4bdrv);
+
+#endif /* __FreeBSD__ */
+
+/*---------------------------------------------------------------------------*
+ * interface attach routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC void
+#ifdef __FreeBSD__
+i4battach(void *dummy)
+#else
+i4battach()
+#endif
+{
+#ifndef HACK_NO_PSEUDO_ATTACH_MSG
+ printf("i4b: ISDN call control device attached\n");
+#endif
+ i4b_rdqueue.ifq_maxlen = IFQ_MAXLEN;
+#ifdef DEVFS
+ devfs_token = devfs_add_devswf(&i4b_cdevsw, 0, DV_CHR,
+ UID_ROOT, GID_WHEEL, 0600,
+ "i4b", 0);
+#endif
+}
+
+/*---------------------------------------------------------------------------*
+ * i4bopen - device driver open routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4bopen(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int x;
+
+ if(minor(dev))
+ return(ENXIO);
+
+ if(openflag)
+ return(EBUSY);
+
+ x = splimp();
+ openflag = 1;
+ i4b_l4_daemon_attached();
+ splx(x);
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * i4bclose - device driver close routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4bclose(dev_t dev, int flag, int fmt, struct proc *p)
+{
+ int x = splimp();
+ openflag = 0;
+ i4b_l4_daemon_detached();
+ i4b_Dcleanifq(&i4b_rdqueue);
+ splx(x);
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * i4bread - device driver read routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4bread(dev_t dev, struct uio *uio, int ioflag)
+{
+ struct mbuf *m;
+ int x;
+ int error = 0;
+
+ if(minor(dev))
+ return(ENODEV);
+
+ while(IF_QEMPTY(&i4b_rdqueue))
+ {
+ x = splimp();
+ readflag = 1;
+ splx(x);
+ tsleep((caddr_t) &i4b_rdqueue, (PZERO + 1) | PCATCH, "bird", 0);
+ }
+
+ x = splimp();
+
+ IF_DEQUEUE(&i4b_rdqueue, m);
+
+ splx(x);
+
+ if(m && m->m_len)
+ error = uiomove(m->m_data, m->m_len, uio);
+ else
+ error = EIO;
+
+ if(m)
+ i4b_Dfreembuf(m);
+
+ return(error);
+}
+
+/*---------------------------------------------------------------------------*
+ * i4bioctl - device driver ioctl routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+#if defined (__FreeBSD_version) && __FreeBSD_version >= 300003
+i4bioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+#else
+i4bioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+#endif
+{
+ call_desc_t *cd;
+ int error = 0;
+
+ if(minor(dev))
+ return(ENODEV);
+
+ switch(cmd)
+ {
+ /* cdid request, reserve cd and return cdid */
+
+ case I4B_CDID_REQ:
+ {
+ msg_cdid_req_t *mir;
+ mir = (msg_cdid_req_t *)data;
+ cd = reserve_cd();
+ mir->cdid = cd->cdid;
+ break;
+ }
+
+ /* connect request, dial out to remote */
+
+ case I4B_CONNECT_REQ:
+ {
+ msg_connect_req_t *mcr;
+ mcr = (msg_connect_req_t *)data; /* setup ptr */
+
+ if((cd = cd_by_cdid(mcr->cdid)) == NULL)/* get cd */
+ {
+ DBGL4(L4_ERR, "i4bioctl", ("I4B_CONNECT_REQ ioctl, cdid not found!\n"));
+ error = EINVAL;
+ break;
+ }
+
+ cd->controller = mcr->controller; /* fill cd */
+ cd->bprot = mcr->bprot;
+ cd->driver = mcr->driver;
+ cd->driver_unit = mcr->driver_unit;
+ cd->cr = get_rand_cr(ctrl_desc[cd->controller].unit);
+
+ cd->unitlen_time = mcr->unitlen_time;
+ cd->idle_time = mcr->idle_time;
+ cd->earlyhup_time = mcr->earlyhup_time;
+
+ cd->last_aocd_time = 0;
+ if(mcr->unitlen_method == ULEN_METHOD_DYNAMIC)
+ cd->aocd_flag = 1;
+ else
+ cd->aocd_flag = 0;
+
+ cd->cunits = 0;
+
+ cd->max_idle_time = 0; /* this is outgoing */
+
+ cd->dir = DIR_OUTGOING;
+
+ DBGL4(L4_TIMO, "i4bioctl", ("I4B_CONNECT_REQ times, unitlen=%ld idle=%ld earlyhup=%ld\n",
+ (long)cd->unitlen_time, (long)cd->idle_time, (long)cd->earlyhup_time));
+
+ strcpy(cd->dst_telno, mcr->dst_telno);
+ strcpy(cd->src_telno, mcr->src_telno);
+ cd->display[0] = '\0';
+
+ SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
+ SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NORMAL);
+
+ switch(mcr->channel)
+ {
+ case CHAN_B1:
+ case CHAN_B2:
+ if(ctrl_desc[mcr->controller].bch_state[mcr->channel] != BCH_ST_FREE)
+ SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
+ break;
+
+ case CHAN_ANY:
+ if((ctrl_desc[mcr->controller].bch_state[CHAN_B1] != BCH_ST_FREE) &&
+ (ctrl_desc[mcr->controller].bch_state[CHAN_B2] != BCH_ST_FREE))
+ SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
+ break;
+
+ default:
+ SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
+ break;
+ }
+
+ cd->channelid = mcr->channel;
+
+ cd->isdntxdelay = mcr->txdelay;
+
+ /* check whether we have a pointer. Seems like */
+ /* this should be adequate. GJ 19.09.97 */
+ if(ctrl_desc[cd->controller].N_CONNECT_REQUEST == NULL)
+/*XXX*/ SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
+
+ if((GET_CAUSE_VAL(cd->cause_in)) != CAUSE_I4B_NORMAL)
+ {
+ i4b_l4_disconnect_ind(cd);
+ freecd_by_cd(cd);
+ }
+ else
+ {
+ (*ctrl_desc[cd->controller].N_CONNECT_REQUEST)(mcr->cdid);
+ }
+ break;
+ }
+
+ /* connect response, accept/reject/ignore incoming call */
+
+ case I4B_CONNECT_RESP:
+ {
+ msg_connect_resp_t *mcrsp;
+
+ mcrsp = (msg_connect_resp_t *)data;
+
+ if((cd = cd_by_cdid(mcrsp->cdid)) == NULL)/* get cd */
+ {
+ DBGL4(L4_ERR, "i4bioctl", ("I4B_CONNECT_RESP ioctl, cdid not found!\n"));
+ error = EINVAL;
+ break;
+ }
+
+ T400_stop(cd);
+
+ cd->driver = mcrsp->driver;
+ cd->driver_unit = mcrsp->driver_unit;
+ cd->max_idle_time = mcrsp->max_idle_time;
+
+ cd->unitlen_time = 0; /* this is incoming */
+ cd->idle_time = 0;
+ cd->earlyhup_time = 0;
+
+ cd->isdntxdelay = mcrsp->txdelay;
+
+ DBGL4(L4_TIMO, "i4bioctl", ("I4B_CONNECT_RESP max_idle_time set to %ld seconds\n", (long)cd->max_idle_time));
+
+ (*ctrl_desc[cd->controller].N_CONNECT_RESPONSE)(mcrsp->cdid, mcrsp->response, mcrsp->cause);
+ break;
+ }
+
+ /* disconnect request, actively terminate connection */
+
+ case I4B_DISCONNECT_REQ:
+ {
+ msg_discon_req_t *mdr;
+
+ mdr = (msg_discon_req_t *)data;
+
+ if((cd = cd_by_cdid(mdr->cdid)) == NULL)/* get cd */
+ {
+ DBGL4(L4_ERR, "i4bioctl", ("I4B_DISCONNECT_REQ ioctl, cdid not found!\n"));
+ error = EINVAL;
+ break;
+ }
+
+ /* preset causes with our cause */
+ cd->cause_in = cd->cause_out = mdr->cause;
+
+ (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(mdr->cdid, mdr->cause);
+ break;
+ }
+
+ /* controller info request */
+
+ case I4B_CTRL_INFO_REQ:
+ {
+ msg_ctrl_info_req_t *mcir;
+
+ mcir = (msg_ctrl_info_req_t *)data;
+ mcir->ncontroller = nctrl;
+
+ if(mcir->controller > nctrl)
+ {
+ mcir->ctrl_type = -1;
+ mcir->card_type = -1;
+ }
+ else
+ {
+ mcir->ctrl_type =
+ ctrl_desc[mcir->controller].ctrl_type;
+ mcir->card_type =
+ ctrl_desc[mcir->controller].card_type;
+
+ if(ctrl_desc[mcir->controller].ctrl_type == CTRL_PASSIVE)
+ mcir->tei = ctrl_desc[mcir->controller].tei;
+ else
+ mcir->tei = -1;
+ }
+ break;
+ }
+
+ /* dial response */
+
+ case I4B_DIALOUT_RESP:
+ {
+ msg_dialout_resp_t *mdrsp;
+
+ mdrsp = (msg_dialout_resp_t *)data;
+
+#if NI4BIPR > 0
+ if(mdrsp->driver == BDRV_IPR)
+ {
+ drvr_link_t *dlt;
+ dlt = ipr_ret_linktab(mdrsp->driver_unit);
+ (*dlt->dial_response)(mdrsp->driver_unit, mdrsp->stat);
+ }
+#endif
+ break;
+ }
+
+ /* update timeout value */
+
+ case I4B_TIMEOUT_UPD:
+ {
+ msg_timeout_upd_t *mtu;
+ int x;
+
+ mtu = (msg_timeout_upd_t *)data;
+
+ if((cd = cd_by_cdid(mtu->cdid)) == NULL)/* get cd */
+ {
+ DBGL4(L4_ERR, "i4bioctl", ("I4B_TIMEOUT_UPD ioctl, cdid not found!\n"));
+ error = EINVAL;
+ break;
+ }
+
+ x = SPLI4B();
+ cd->unitlen_time = mtu->unitlen_time;
+ cd->idle_time = mtu->idle_time;
+ cd->earlyhup_time = mtu->earlyhup_time;
+ splx(x);
+ break;
+ }
+
+ /* soft enable/disable interface */
+
+ case I4B_UPDOWN_IND:
+ {
+ msg_updown_ind_t *mui;
+
+ mui = (msg_updown_ind_t *)data;
+
+#if NI4BIPR > 0
+ if(mui->driver == BDRV_IPR)
+ {
+ drvr_link_t *dlt;
+ dlt = ipr_ret_linktab(mui->driver_unit);
+ (*dlt->updown_ind)(mui->driver_unit, mui->updown);
+ }
+#endif
+ break;
+ }
+
+ /* send ALERT request */
+
+ case I4B_ALERT_REQ:
+ {
+ msg_alert_req_t *mar;
+
+ mar = (msg_alert_req_t *)data;
+
+ if((cd = cd_by_cdid(mar->cdid)) == NULL)
+ {
+ DBGL4(L4_ERR, "i4bioctl", ("I4B_ALERT_REQ ioctl, cdid not found!\n"));
+ error = EINVAL;
+ break;
+ }
+
+ T400_stop(cd);
+
+ (*ctrl_desc[cd->controller].N_ALERT_REQUEST)(mar->cdid);
+
+ break;
+ }
+
+ /* version/release number request */
+
+ case I4B_VR_REQ:
+ {
+ msg_vr_req_t *mvr;
+
+ mvr = (msg_vr_req_t *)data;
+
+ mvr->version = VERSION;
+ mvr->release = REL;
+ mvr->step = STEP;
+ break;
+ }
+
+ /* Download request */
+
+ case I4B_CTRL_DOWNLOAD:
+ {
+ struct isdn_dr_prot *prots = NULL, *prots2 = NULL;
+ struct isdn_download_request *r =
+ (struct isdn_download_request*)data;
+ int i;
+
+ if(!ctrl_desc[r->controller].N_DOWNLOAD)
+ {
+ error = ENODEV;
+ goto download_done;
+ }
+
+ prots = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
+ M_DEVBUF, M_WAITOK);
+
+ prots2 = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
+ M_DEVBUF, M_WAITOK);
+
+ if(!prots || !prots2)
+ {
+ error = ENOMEM;
+ goto download_done;
+ }
+
+ copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot));
+
+ for(i = 0; i < r->numprotos; i++)
+ {
+ prots2[i].microcode = malloc(prots[i].bytecount, M_DEVBUF, M_WAITOK);
+ copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount);
+ prots2[i].bytecount = prots[i].bytecount;
+ }
+
+ error = ctrl_desc[r->controller].N_DOWNLOAD(
+ ctrl_desc[r->controller].unit,
+ r->numprotos, prots2);
+
+download_done:
+ if(prots2)
+ {
+ for(i = 0; i < r->numprotos; i++)
+ {
+ if(prots2[i].microcode)
+ {
+ free(prots2[i].microcode, M_DEVBUF);
+ }
+ }
+ free(prots2, M_DEVBUF);
+ }
+
+ if(prots)
+ {
+ free(prots, M_DEVBUF);
+ }
+ break;
+ }
+
+ /* Diagnostic request */
+
+ case I4B_ACTIVE_DIAGNOSTIC:
+ {
+ struct isdn_diagnostic_request req, *r =
+ (struct isdn_diagnostic_request*)data;
+
+ req.in_param = req.out_param = NULL;
+
+ if(!ctrl_desc[r->controller].N_DIAGNOSTICS)
+ {
+ error = ENODEV;
+ goto diag_done;
+ }
+
+ memcpy(&req, r, sizeof(req));
+
+ if(req.in_param_len)
+ {
+ req.in_param = malloc(r->in_param_len, M_DEVBUF, M_WAITOK);
+
+ if(!req.in_param)
+ {
+ error = ENOMEM;
+ goto diag_done;
+ }
+ copyin(r->in_param, req.in_param, req.in_param_len);
+ }
+
+ if(req.out_param_len)
+ {
+ req.out_param = malloc(r->out_param_len, M_DEVBUF, M_WAITOK);
+
+ if(!req.out_param)
+ {
+ error = ENOMEM;
+ goto diag_done;
+ }
+ }
+
+ error = ctrl_desc[r->controller].N_DIAGNOSTICS(r->controller, &req);
+
+ if(!error && req.out_param_len)
+ copyout(req.out_param, r->out_param, req.out_param_len);
+
+diag_done:
+ if(req.in_param)
+ free(req.in_param, M_DEVBUF);
+
+ if(req.out_param)
+ free(req.out_param, M_DEVBUF);
+
+ break;
+ }
+
+ /* default */
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+
+ return(error);
+}
+
+#if (defined(__FreeBSD__) && \
+ (!defined(__FreeBSD_version) || (__FreeBSD_version < 300001))) \
+ || defined (__OpenBSD__)
+
+/*---------------------------------------------------------------------------*
+ * i4bselect - device driver select routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4bselect(dev_t dev, int rw, struct proc *p)
+{
+ int x;
+
+ if(minor(dev))
+ return(ENODEV);
+
+ switch(rw)
+ {
+ case FREAD:
+ if(!IF_QEMPTY(&i4b_rdqueue))
+ return(1);
+ x = splimp();
+ selrecord(p, &select_rd_info);
+ selflag = 1;
+ splx(x);
+ return(0);
+ break;
+
+ case FWRITE:
+ return(1);
+ break;
+ }
+ return(0);
+}
+
+#else /* NetBSD and FreeBSD -current */
+
+/*---------------------------------------------------------------------------*
+ * i4bpoll - device driver poll routine
+ *---------------------------------------------------------------------------*/
+PDEVSTATIC int
+i4bpoll(dev_t dev, int events, struct proc *p)
+{
+ int x;
+
+ if(minor(dev))
+ return(ENODEV);
+
+ if((events & POLLIN) || (events & POLLRDNORM))
+ {
+ if(!IF_QEMPTY(&i4b_rdqueue))
+ return(1);
+
+ x = splimp();
+ selrecord(p, &select_rd_info);
+ selflag = 1;
+ splx(x);
+ return(0);
+ }
+ else if((events & POLLOUT) || (events & POLLWRNORM))
+ {
+ return(1);
+ }
+
+ return(0);
+}
+
+#endif /* defined(__FreeBSD__) && __FreeBSD__ < 3 */
+
+/*---------------------------------------------------------------------------*
+ * i4bputqueue - put message into queue to userland
+ *---------------------------------------------------------------------------*/
+void
+i4bputqueue(struct mbuf *m)
+{
+ int x;
+
+ if(!openflag)
+ {
+ i4b_Dfreembuf(m);
+ return;
+ }
+
+ x = splimp();
+
+ if(IF_QFULL(&i4b_rdqueue))
+ {
+ struct mbuf *m1;
+ IF_DEQUEUE(&i4b_rdqueue, m1);
+ i4b_Dfreembuf(m1);
+ DBGL4(L4_ERR, "i4bputqueue", ("ERROR, queue full, removing entry!\n"));
+ }
+
+ IF_ENQUEUE(&i4b_rdqueue, m);
+
+ splx(x);
+
+ if(readflag)
+ {
+ readflag = 0;
+ wakeup((caddr_t) &i4b_rdqueue);
+ }
+
+ if(selflag)
+ {
+ selflag = 0;
+ selwakeup(&select_rd_info);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * i4bputqueue_hipri - put message into front of queue to userland
+ *---------------------------------------------------------------------------*/
+void
+i4bputqueue_hipri(struct mbuf *m)
+{
+ int x;
+
+ if(!openflag)
+ {
+ i4b_Dfreembuf(m);
+ return;
+ }
+
+ x = splimp();
+
+ if(IF_QFULL(&i4b_rdqueue))
+ {
+ struct mbuf *m1;
+ IF_DEQUEUE(&i4b_rdqueue, m1);
+ i4b_Dfreembuf(m1);
+ DBGL4(L4_ERR, "i4bputqueue", ("ERROR, queue full, removing entry!\n"));
+ }
+
+ IF_PREPEND(&i4b_rdqueue, m);
+
+ splx(x);
+
+ if(readflag)
+ {
+ readflag = 0;
+ wakeup((caddr_t) &i4b_rdqueue);
+ }
+
+ if(selflag)
+ {
+ selflag = 0;
+ selwakeup(&select_rd_info);
+ }
+}
+
+#if BSD > 199306 && defined(__FreeBSD__)
+static i4b_devsw_installed = 0;
+
+static void
+i4b_drvinit(void *unused)
+{
+ dev_t dev;
+
+ if( ! i4b_devsw_installed ) {
+ dev = makedev(CDEV_MAJOR,0);
+ cdevsw_add(&dev,&i4b_cdevsw,NULL);
+ i4b_devsw_installed = 1;
+ }
+}
+
+SYSINIT(i4bdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,i4b_drvinit,NULL)
+#endif /* __FreeBSD__ */
+#endif /* NI4B > 0 */
diff --git a/sys/i4b/layer4/i4b_l4.c b/sys/i4b/layer4/i4b_l4.c
new file mode 100644
index 0000000..cecd5f4
--- /dev/null
+++ b/sys/i4b/layer4/i4b_l4.c
@@ -0,0 +1,897 @@
+/*
+ * 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_l4.c - kernel interface to userland
+ * -----------------------------------------
+ *
+ * $Id: i4b_l4.c,v 1.33 1998/12/05 18:05:49 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:35:16 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "i4b.h"
+#include "i4bipr.h"
+#include "i4bisppp.h"
+#include "i4brbch.h"
+#include "i4btel.h"
+
+#if NI4B > 0
+
+#include <sys/param.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <sys/ioccom.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 <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_cause.h>
+#else
+#include <i4b/i4b_debug.h>
+#include <i4b/i4b_ioctl.h>
+#include <i4b/i4b_cause.h>
+#endif
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/layer3/i4b_l3.h>
+#include <i4b/layer4/i4b_l4.h>
+
+unsigned int i4b_l4_debug = L4_DEBUG_DEFAULT;
+
+struct ctrl_type_desc ctrl_types[CTRL_NUMTYPES] = { { NULL, NULL} };
+
+static int i4b_link_bchandrvr(call_desc_t *cd);
+static void i4b_unlink_bchandrvr(call_desc_t *cd);
+static void i4b_l4_setup_timeout(call_desc_t *cd);
+
+/*---------------------------------------------------------------------------*
+ * send MSG_PDEACT_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_pdeact(int controller, int numactive)
+{
+ struct mbuf *m;
+ int i;
+ call_desc_t *cd;
+
+ for(i=0; i < N_CALL_DESC; i++)
+ {
+ if((call_desc[i].cdid != CDID_UNUSED) &&
+ (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) &&
+ (ctrl_desc[call_desc[i].controller].unit == controller))
+ {
+ cd = &call_desc[i];
+
+ if(cd->timeout_active)
+ {
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+ untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, cd->idle_timeout_handle);
+#else
+ untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd);
+#endif
+ }
+
+ if(cd->dlt != NULL)
+ {
+ (*cd->dlt->line_disconnected)(cd->driver_unit, (void *)cd);
+ i4b_unlink_bchandrvr(cd);
+ }
+
+ if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2))
+ {
+ ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE;
+ }
+
+ cd->cdid = CDID_UNUSED;
+ }
+ }
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_pdeact_ind_t))) != NULL)
+ {
+ msg_pdeact_ind_t *md = (msg_pdeact_ind_t *)m->m_data;
+
+ md->header.type = MSG_PDEACT_IND;
+ md->header.cdid = -1;
+
+ md->controller = controller;
+ md->numactive = numactive;
+
+ i4bputqueue_hipri(m); /* URGENT !!! */
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_L12STAT_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_l12stat(int controller, int layer, int state)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_l12stat_ind_t))) != NULL)
+ {
+ msg_l12stat_ind_t *md = (msg_l12stat_ind_t *)m->m_data;
+
+ md->header.type = MSG_L12STAT_IND;
+ md->header.cdid = -1;
+
+ md->controller = controller;
+ md->layer = layer;
+ md->state = state;
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_TEIASG_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_teiasg(int controller, int tei)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_teiasg_ind_t))) != NULL)
+ {
+ msg_teiasg_ind_t *md = (msg_teiasg_ind_t *)m->m_data;
+
+ md->header.type = MSG_TEIASG_IND;
+ md->header.cdid = -1;
+
+ md->controller = controller;
+ md->tei = ctrl_desc[controller].tei;
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_DIALOUT_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_dialout(int driver, int driver_unit)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_dialout_ind_t))) != NULL)
+ {
+ msg_dialout_ind_t *md = (msg_dialout_ind_t *)m->m_data;
+
+ md->header.type = MSG_DIALOUT_IND;
+ md->header.cdid = -1;
+
+ md->driver = driver;
+ md->driver_unit = driver_unit;
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_NEGOTIATION_COMPL message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_negcomplete(call_desc_t *cd)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_negcomplete_ind_t))) != NULL)
+ {
+ msg_negcomplete_ind_t *md = (msg_negcomplete_ind_t *)m->m_data;
+
+ md->header.type = MSG_NEGCOMP_IND;
+ md->header.cdid = cd->cdid;
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_IFSTATE_CHANGED_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_ifstate_changed(call_desc_t *cd, int new_state)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_ifstatechg_ind_t))) != NULL)
+ {
+ msg_ifstatechg_ind_t *md = (msg_ifstatechg_ind_t *)m->m_data;
+
+ md->header.type = MSG_IFSTATE_CHANGED_IND;
+ md->header.cdid = cd->cdid;
+ md->state = new_state;
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_DRVRDISC_REQ message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_drvrdisc(int driver, int driver_unit)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_drvrdisc_req_t))) != NULL)
+ {
+ msg_drvrdisc_req_t *md = (msg_drvrdisc_req_t *)m->m_data;
+
+ md->header.type = MSG_DRVRDISC_REQ;
+ md->header.cdid = -1;
+
+ md->driver = driver;
+ md->driver_unit = driver_unit;
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_ACCT_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_accounting(int driver, int driver_unit, int accttype, int ioutbytes,
+ int iinbytes, int ro, int ri, int outbytes, int inbytes)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_accounting_ind_t))) != NULL)
+ {
+ msg_accounting_ind_t *md = (msg_accounting_ind_t *)m->m_data;
+
+ md->header.type = MSG_ACCT_IND;
+ md->header.cdid = -1;
+
+ md->driver = driver;
+ md->driver_unit = driver_unit;
+
+ md->accttype = accttype;
+ md->ioutbytes = ioutbytes;
+ md->iinbytes = iinbytes;
+ md->outbps = ro;
+ md->inbps = ri;
+ md->outbytes = outbytes;
+ md->inbytes = inbytes;
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_CONNECT_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_connect_ind(call_desc_t *cd)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_connect_ind_t))) != NULL)
+ {
+ msg_connect_ind_t *mp = (msg_connect_ind_t *)m->m_data;
+
+ mp->header.type = MSG_CONNECT_IND;
+ mp->header.cdid = cd->cdid;
+
+ mp->controller = cd->controller;
+ mp->channel = cd->channelid;
+ mp->bprot = cd->bprot;
+
+ cd->dir = DIR_INCOMING;
+
+ if(strlen(cd->dst_telno) > 0)
+ strcpy(mp->dst_telno, cd->dst_telno);
+ else
+ strcpy(mp->dst_telno, TELNO_EMPTY);
+
+ if(strlen(cd->src_telno) > 0)
+ strcpy(mp->src_telno, cd->src_telno);
+ else
+ strcpy(mp->src_telno, TELNO_EMPTY);
+
+ strcpy(mp->display, cd->display);
+
+ mp->scr_ind = cd->scr_ind;
+
+ T400_start(cd);
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_CONNECT_ACTIVE_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_connect_active_ind(call_desc_t *cd)
+{
+ int s;
+ struct mbuf *m;
+
+ s = SPLI4B();
+
+ cd->last_active_time = cd->connect_time = SECOND;
+
+ DBGL4(L4_TIMO, "i4b_l4_connect_active_ind", ("last_active/connect_time=%ld\n", (long)cd->connect_time));
+
+ i4b_link_bchandrvr(cd);
+
+ (*cd->dlt->line_connected)(cd->driver_unit, (void *)cd);
+
+ i4b_l4_setup_timeout(cd);
+
+ splx(s);
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_connect_active_ind_t))) != NULL)
+ {
+ msg_connect_active_ind_t *mp = (msg_connect_active_ind_t *)m->m_data;
+
+ mp->header.type = MSG_CONNECT_ACTIVE_IND;
+ mp->header.cdid = cd->cdid;
+ mp->controller = cd->controller;
+ mp->channel = cd->channelid;
+ if(cd->datetime[0] != '\0')
+ strcpy(mp->datetime, cd->datetime);
+ else
+ mp->datetime[0] = '\0';
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_DISCONNECT_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_disconnect_ind(call_desc_t *cd)
+{
+ struct mbuf *m;
+
+ if(cd->timeout_active)
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, cd->idle_timeout_handle);
+#else
+ untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd);
+#endif
+
+ if(cd->dlt != NULL)
+ {
+ (*cd->dlt->line_disconnected)(cd->driver_unit, (void *)cd);
+ i4b_unlink_bchandrvr(cd);
+ }
+
+ if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2))
+ {
+ ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE;
+ }
+ else
+ {
+ /* no error, might be hunting call for callback */
+ DBGL4(L4_MSG, "i4b_l4_disconnect_ind", ("channel free not B1/B2 but %d!\n", cd->channelid));
+ }
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_disconnect_ind_t))) != NULL)
+ {
+ msg_disconnect_ind_t *mp = (msg_disconnect_ind_t *)m->m_data;
+
+ mp->header.type = MSG_DISCONNECT_IND;
+ mp->header.cdid = cd->cdid;
+ mp->cause = cd->cause_in;
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_IDLE_TIMEOUT_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_idle_timeout_ind(call_desc_t *cd)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_idle_timeout_ind_t))) != NULL)
+ {
+ msg_idle_timeout_ind_t *mp = (msg_idle_timeout_ind_t *)m->m_data;
+
+ mp->header.type = MSG_IDLE_TIMEOUT_IND;
+ mp->header.cdid = cd->cdid;
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_CHARGING_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_charging_ind(call_desc_t *cd)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_charging_ind_t))) != NULL)
+ {
+ msg_charging_ind_t *mp = (msg_charging_ind_t *)m->m_data;
+
+ mp->header.type = MSG_CHARGING_IND;
+ mp->header.cdid = cd->cdid;
+ mp->units_type = cd->units_type;
+
+/*XXX*/ if(mp->units_type == CHARGE_CALC)
+ mp->units = cd->cunits;
+ else
+ mp->units = cd->units;
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_STATUS_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_status_ind(call_desc_t *cd)
+{
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_ALERT_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_alert_ind(call_desc_t *cd)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_alert_ind_t))) != NULL)
+ {
+ msg_alert_ind_t *mp = (msg_alert_ind_t *)m->m_data;
+
+ mp->header.type = MSG_ALERT_IND;
+ mp->header.cdid = cd->cdid;
+
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_INFO_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_info_ind(call_desc_t *cd)
+{
+}
+
+/*---------------------------------------------------------------------------*
+ * send MSG_INFO_IND message to userland
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_proceeding_ind(call_desc_t *cd)
+{
+ struct mbuf *m;
+
+ if((m = i4b_Dgetmbuf(sizeof(msg_proceeding_ind_t))) != NULL)
+ {
+ msg_proceeding_ind_t *mp = (msg_proceeding_ind_t *)m->m_data;
+
+ mp->header.type = MSG_PROCEEDING_IND;
+ mp->header.cdid = cd->cdid;
+ mp->controller = cd->controller;
+ mp->channel = cd->channelid;
+ i4bputqueue(m);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * link a driver(unit) to a B-channel(controller,unit,channel)
+ *---------------------------------------------------------------------------*/
+static int
+i4b_link_bchandrvr(call_desc_t *cd)
+{
+ int t = ctrl_desc[cd->controller].ctrl_type;
+
+ if(t < 0 || t >= CTRL_NUMTYPES || ctrl_types[t].get_linktab == NULL)
+ {
+ cd->ilt = NULL;
+ }
+ else
+ {
+ cd->ilt = ctrl_types[t].get_linktab(
+ ctrl_desc[cd->controller].unit,
+ cd->channelid);
+ }
+
+ switch(cd->driver)
+ {
+#if NI4BRBCH > 0
+ case BDRV_RBCH:
+ cd->dlt = rbch_ret_linktab(cd->driver_unit);
+ break;
+#endif
+
+#if NI4BTEL > 0
+ case BDRV_TEL:
+ cd->dlt = tel_ret_linktab(cd->driver_unit);
+ break;
+#endif
+
+#if NI4BIPR > 0
+ case BDRV_IPR:
+ cd->dlt = ipr_ret_linktab(cd->driver_unit);
+ break;
+#endif
+
+#if NI4BISPPP > 0
+ case BDRV_ISPPP:
+ cd->dlt = i4bisppp_ret_linktab(cd->driver_unit);
+ break;
+#endif
+
+ default:
+ cd->dlt = NULL;
+ break;
+ }
+
+ if(cd->dlt == NULL || cd->ilt == NULL)
+ return(-1);
+
+ if(t >= 0 && t < CTRL_NUMTYPES && ctrl_types[t].set_linktab != NULL)
+ {
+ ctrl_types[t].set_linktab(
+ ctrl_desc[cd->controller].unit,
+ cd->channelid,
+ cd->dlt);
+ }
+
+ switch(cd->driver)
+ {
+#if NI4BRBCH > 0
+ case BDRV_RBCH:
+ rbch_set_linktab(cd->driver_unit, cd->ilt);
+ break;
+#endif
+
+#if NI4BTEL > 0
+ case BDRV_TEL:
+ tel_set_linktab(cd->driver_unit, cd->ilt);
+ break;
+#endif
+
+#if NI4BIPR > 0
+ case BDRV_IPR:
+ ipr_set_linktab(cd->driver_unit, cd->ilt);
+ break;
+#endif
+
+#if NI4BISPPP > 0
+ case BDRV_ISPPP:
+ i4bisppp_set_linktab(cd->driver_unit, cd->ilt);
+ break;
+#endif
+ default:
+ return(0);
+ break;
+ }
+
+ /* activate B channel */
+
+ (*cd->ilt->bch_config)(ctrl_desc[cd->controller].unit,
+ cd->channelid, cd->bprot, 1);
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * unlink a driver(unit) from a B-channel(controller,unit,channel)
+ *---------------------------------------------------------------------------*/
+static void
+i4b_unlink_bchandrvr(call_desc_t *cd)
+{
+ int t = ctrl_desc[cd->controller].ctrl_type;
+
+ if(t < 0 || t >= CTRL_NUMTYPES || ctrl_types[t].get_linktab == NULL)
+ {
+ cd->ilt = NULL;
+ return;
+ }
+ else
+ {
+ cd->ilt = ctrl_types[t].get_linktab(
+ ctrl_desc[cd->controller].unit,
+ cd->channelid);
+ }
+
+ /* deactivate B channel */
+
+ (*cd->ilt->bch_config)(ctrl_desc[cd->controller].unit,
+ cd->channelid, cd->bprot, 0);
+}
+
+/*---------------------------------------------------------------------------
+
+ How shorthold mode works for OUTGOING connections
+ =================================================
+
+ |<---- unchecked-window ------->|<-checkwindow->|<-safetywindow>|
+
+idletime_state: IST_NONCHK IST_CHECK IST_SAFE
+
+ | | | |
+ time>>+-------------------------------+---------------+---------------+-...
+ | | | |
+ | |<--idle_time-->|<--earlyhup--->|
+ |<-----------------------unitlen------------------------------->|
+
+
+ unitlen - specifies the time a charging unit lasts
+ idle_time - specifies the thime the line must be idle at the
+ end of the unit to be elected for hangup
+ earlyhup - is the beginning of a timing safety zone before the
+ next charging unit starts
+
+ The algorithm works as follows: lets assume the unitlen is 100
+ secons, idle_time is 40 seconds and earlyhup is 10 seconds.
+ The line then must be idle 50 seconds after the begin of the
+ current unit and it must then be quiet for 40 seconds. if it
+ has been quiet for this 40 seconds, the line is closed 10
+ seconds before the next charging unit starts. In case there was
+ any traffic within the idle_time, the line is not closed.
+ It does not matter whether there was any traffic between second
+ 0 and second 50 or not.
+
+
+ How shorthold mode works for INCOMING connections
+ =================================================
+
+ it is just possible to specify a maximum idle time for incoming
+ connections, after this time of no activity on the line the line
+ is closed.
+
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*
+ * B channel idle check timeout setup
+ *---------------------------------------------------------------------------*/
+static void
+i4b_l4_setup_timeout(call_desc_t *cd)
+{
+ cd->timeout_active = 0;
+ cd->idletime_state = IST_IDLE;
+
+ if((cd->dir == DIR_INCOMING) && (cd->max_idle_time > 0))
+ {
+ /* incoming call: simple max idletime check */
+
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ cd->idle_timeout_handle =
+#endif
+ timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2);
+ cd->timeout_active = 1;
+ DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: incoming-call, setup max_idle_time to %ld\n", (long)SECOND, (long)cd->max_idle_time));
+ }
+ else if((cd->dir == DIR_OUTGOING) && (cd->idle_time > 0))
+ {
+ /* outgoing call */
+
+ if((cd->idle_time > 0) && (cd->unitlen_time == 0))
+ {
+ /* outgoing call: simple max idletime check */
+
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ cd->idle_timeout_handle =
+#endif
+ timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2);
+ cd->timeout_active = 1;
+ DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: outgoing-call, setup idle_time to %ld\n", (long)SECOND, (long)cd->idle_time));
+ }
+ else if((cd->unitlen_time > 0) && (cd->unitlen_time > (cd->idle_time + cd->earlyhup_time)))
+ {
+ /* outgoing call: full shorthold mode check */
+
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ cd->idle_timeout_handle =
+#endif
+ timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->unitlen_time - (cd->idle_time + cd->earlyhup_time)));
+ cd->timeout_active = 1;
+ cd->idletime_state = IST_NONCHK;
+ DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: outgoing-call, start %ld sec nocheck window\n",
+ (long)SECOND, (long)(cd->unitlen_time - (cd->idle_time + cd->earlyhup_time))));
+
+ if(cd->aocd_flag == 0)
+ {
+ cd->units_type = CHARGE_CALC;
+ cd->cunits++;
+ i4b_l4_charging_ind(cd);
+ }
+ }
+ else
+ {
+ /* parms somehow got wrong .. */
+
+ DBGL4(L4_ERR, "i4b_l4_setup_timeout", ("%ld: ERROR: idletime[%ld]+earlyhup[%ld] > unitlength[%ld]!\n",
+ (long)SECOND, (long)cd->idle_time, (long)cd->earlyhup_time, (long)cd->unitlen_time));
+ }
+ }
+ else
+ {
+ DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("no idle_timeout configured\n"));
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * B channel idle check timeout function
+ *---------------------------------------------------------------------------*/
+void
+i4b_idle_check(call_desc_t *cd)
+{
+ int s;
+
+ if(cd->cdid == CDID_UNUSED)
+ return;
+
+ s = SPLI4B();
+
+ /* failsafe */
+
+ if(cd->timeout_active == 0)
+ {
+ DBGL4(L4_ERR, "i4b_idle_check", ("ERROR: timeout_active == 0 !!!\n"));
+ }
+ else
+ {
+ cd->timeout_active = 0;
+ }
+
+ /* incoming connections, simple idletime check */
+
+ if(cd->dir == DIR_INCOMING)
+ {
+ if((cd->last_active_time + cd->max_idle_time) <= SECOND)
+ {
+ DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: incoming-call, line idle timeout, disconnecting!\n", (long)SECOND));
+ (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid,
+ (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
+ i4b_l4_idle_timeout_ind(cd);
+ }
+ else
+ {
+ DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: incoming-call, activity, last_active=%ld, max_idle=%ld\n", (long)SECOND, (long)cd->last_active_time, (long)cd->max_idle_time));
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ cd->idle_timeout_handle =
+#endif
+ timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2);
+ cd->timeout_active = 1;
+ }
+ }
+
+ /* outgoing connections */
+
+ else if(cd->dir == DIR_OUTGOING)
+ {
+
+ /* simple idletime calculation */
+
+ if((cd->idle_time > 0) && (cd->unitlen_time == 0))
+ {
+ if((cd->last_active_time + cd->idle_time) <= SECOND)
+ {
+ DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call-st, idle timeout, disconnecting!\n", (long)SECOND));
+ (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid,
+ (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
+ i4b_l4_idle_timeout_ind(cd);
+ }
+ else
+ {
+ DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call-st, activity, last_active=%ld, max_idle=%ld\n",
+ (long)SECOND, (long)cd->last_active_time, (long)cd->idle_time));
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ cd->idle_timeout_handle =
+#endif
+ timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2);
+ cd->timeout_active = 1;
+ }
+ }
+
+ /* full shorthold mode calculation */
+
+ else if((cd->unitlen_time > 0) && (cd->unitlen_time > (cd->idle_time + cd->earlyhup_time)))
+ {
+ switch(cd->idletime_state)
+ {
+ case IST_NONCHK: /* end of non-check time */
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ cd->idle_timeout_handle =
+#endif
+ timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->idle_time));
+ cd->idletimechk_start = SECOND;
+ cd->idletime_state = IST_CHECK;
+ cd->timeout_active = 1;
+ DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, idletime check window reached!\n", (long)SECOND));
+ break;
+
+ case IST_CHECK: /* end of idletime chk */
+ if((cd->last_active_time > cd->idletimechk_start) &&
+ (cd->last_active_time <= SECOND))
+ { /* activity detected */
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ cd->idle_timeout_handle =
+#endif
+ timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->earlyhup_time));
+ cd->timeout_active = 1;
+ cd->idletime_state = IST_SAFE;
+ DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, activity at %ld, wait earlyhup-end\n", (long)SECOND, (long)cd->last_active_time));
+ }
+ else
+ { /* no activity, hangup */
+ DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, idle timeout, last activity at %ld\n", (long)SECOND, (long)cd->last_active_time));
+ (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid,
+ (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
+ i4b_l4_idle_timeout_ind(cd);
+ cd->idletime_state = IST_IDLE;
+ }
+ break;
+
+ case IST_SAFE: /* end of earlyhup time */
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ cd->idle_timeout_handle =
+#endif
+ timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->unitlen_time - (cd->idle_time+cd->earlyhup_time)));
+ cd->timeout_active = 1;
+ cd->idletime_state = IST_NONCHK;
+
+ if(cd->aocd_flag == 0)
+ {
+ cd->units_type = CHARGE_CALC;
+ cd->cunits++;
+ i4b_l4_charging_ind(cd);
+ }
+
+ DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, earlyhup end, wait for idletime start\n", (long)SECOND));
+ break;
+
+ default:
+ DBGL4(L4_ERR, "i4b_idle_check", ("outgoing-call: invalid idletime_state value!\n"));
+ cd->idletime_state = IST_IDLE;
+ break;
+ }
+ }
+ }
+ splx(s);
+}
+
+#endif /* NI4B > 0 */
diff --git a/sys/i4b/layer4/i4b_l4.h b/sys/i4b/layer4/i4b_l4.h
new file mode 100644
index 0000000..e4ed863f
--- /dev/null
+++ b/sys/i4b/layer4/i4b_l4.h
@@ -0,0 +1,69 @@
+/*
+ * 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_l4.h - kernel interface to userland header file
+ * ---------------------------------------------------
+ *
+ * $Id: i4b_l4.h,v 1.13 1998/12/05 18:05:50 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:35:34 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef _I4B_L4_H_
+#define _I4B_L4_H_
+
+extern void i4bputqueue ( struct mbuf *m );
+extern void i4bputqueue_hipri(struct mbuf *m);
+extern void i4b_l4_accounting(int, int, int, int, int, int, int, int, int);
+extern void i4b_l4_alert_ind ( call_desc_t *cd );
+extern void i4b_l4_charging_ind( call_desc_t *cd );
+extern void i4b_l4_connect_active_ind ( call_desc_t *cd );
+extern void i4b_l4_connect_ind ( call_desc_t *cd );
+extern void i4b_l4_daemon_attached(void);
+extern void i4b_l4_daemon_detached(void);
+extern void i4b_l4_dialout( int driver, int driver_unit );
+extern void i4b_l4_disconnect_ind ( call_desc_t *cd );
+extern void i4b_l4_drvrdisc (int driver, int driver_unit );
+extern void i4b_l4_negcomplete( call_desc_t *cd );
+extern void i4b_l4_ifstate_changed( call_desc_t *cd, int new_state );
+extern void i4b_l4_idle_timeout_ind( call_desc_t *cd );
+extern void i4b_l4_info_ind ( call_desc_t *cd );
+extern void i4b_l4_l12stat(int controller, int layer, int state);
+extern void i4b_l4_pdeact(int controller, int numactive);
+extern void i4b_l4_teiasg(int controller, int tei);
+extern void i4b_l4_status_ind ( call_desc_t *cd );
+extern void i4b_l4_proceeding_ind ( call_desc_t *cd );
+extern void i4b_idle_check(call_desc_t *cdp);
+extern call_desc_t * cd_by_cdid ( unsigned int cdid );
+extern call_desc_t * cd_by_unitcr ( int unit, int cr, int crf );
+extern void freecd_by_cd ( call_desc_t *cd );
+extern unsigned char get_rand_cr ( int unit );
+extern call_desc_t * reserve_cd ( void );
+extern void T400_start ( call_desc_t *cd );
+extern void T400_stop ( call_desc_t *cd );
+
+#endif /* _I4B_L4_H_ */
diff --git a/sys/i4b/layer4/i4b_l4mgmt.c b/sys/i4b/layer4/i4b_l4mgmt.c
new file mode 100644
index 0000000..e8e1a96
--- /dev/null
+++ b/sys/i4b/layer4/i4b_l4mgmt.c
@@ -0,0 +1,467 @@
+/*
+ * 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_l4mgmt.c - layer 4 calldescriptor management utilites
+ * -----------------------------------------------------------
+ *
+ * $Id: i4b_l4mgmt.c,v 1.23 1998/12/05 18:05:52 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:35:50 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "i4b.h"
+
+#if NI4B > 0
+
+#include <sys/param.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+#include <sys/ioccom.h>
+#else
+#include <sys/ioctl.h>
+#endif
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#ifdef __FreeBSD__
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+#include <machine/random.h>
+#endif
+#else
+#include <i4b/i4b_debug.h>
+#include <i4b/i4b_ioctl.h>
+#endif
+
+#include <i4b/include/i4b_l2l3.h>
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_isdnq931.h>
+#include <i4b/include/i4b_global.h>
+
+#include <i4b/layer4/i4b_l4.h>
+
+call_desc_t call_desc[N_CALL_DESC]; /* call descriptor array */
+
+static unsigned int get_cdid(void);
+
+int nctrl; /* number of attached controllers */
+
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+void init_callout(call_desc_t *);
+#endif
+
+/*---------------------------------------------------------------------------*
+ * return a new unique call descriptor id
+ * --------------------------------------
+ * returns a new calldescriptor id which is used to uniquely identyfy
+ * a single call in the communication between kernel and userland.
+ * this cdid is then used to associate a calldescriptor with an id.
+ *---------------------------------------------------------------------------*/
+static unsigned int
+get_cdid(void)
+{
+ static unsigned int cdid_count = 0;
+ int i;
+ int x;
+
+ x = SPLI4B();
+
+ /* get next id */
+
+ cdid_count++;
+
+again:
+ if(cdid_count == CDID_UNUSED) /* zero is invalid */
+ cdid_count++;
+ else if(cdid_count > CDID_MAX) /* wraparound ? */
+ cdid_count = 1;
+
+ /* check if id already in use */
+
+ for(i=0; i < N_CALL_DESC; i++)
+ {
+ if(call_desc[i].cdid == cdid_count)
+ {
+ cdid_count++;
+ goto again;
+ }
+ }
+
+ splx(x);
+
+ return(cdid_count);
+}
+
+/*---------------------------------------------------------------------------*
+ * reserve a calldescriptor for later usage
+ * ----------------------------------------
+ * searches the calldescriptor array until an unused
+ * descriptor is found, gets a new calldescriptor id
+ * and reserves it by putting the id into the cdid field.
+ * returns pointer to the calldescriptor.
+ *---------------------------------------------------------------------------*/
+call_desc_t *
+reserve_cd(void)
+{
+ call_desc_t *cd;
+ int x;
+ int i;
+
+ x = SPLI4B();
+
+ cd = NULL;
+
+ for(i=0; i < N_CALL_DESC; i++)
+ {
+ if(call_desc[i].cdid == CDID_UNUSED)
+ {
+ bzero(&call_desc[i], sizeof(call_desc_t)); /* clear it */
+ call_desc[i].cdid = get_cdid(); /* fill in new cdid */
+ cd = &(call_desc[i]); /* get pointer to descriptor */
+ DBGL4(L4_MSG, "reserve_cd", ("found free cd - index=%d cdid=%u\n",
+ i, call_desc[i].cdid));
+ break;
+ }
+ }
+
+ splx(x);
+
+ if(cd == NULL)
+ panic("reserve_cd: no free call descriptor available!");
+
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ init_callout(cd);
+#endif
+
+ return(cd);
+}
+
+/*---------------------------------------------------------------------------*
+ * free a calldescriptor
+ * ---------------------
+ * free a unused calldescriptor by giving address of calldescriptor
+ * and writing a 0 into the cdid field marking it as unused.
+ *---------------------------------------------------------------------------*/
+void
+freecd_by_cd(call_desc_t *cd)
+{
+ int i;
+ int x = SPLI4B();
+
+ for(i=0; i < N_CALL_DESC; i++)
+ {
+ if( (call_desc[i].cdid != CDID_UNUSED) &&
+ (&(call_desc[i]) == cd) )
+ {
+ DBGL4(L4_MSG, "freecd_by_cd", ("releasing cd - index=%d cdid=%u cr=%d\n",
+ i, call_desc[i].cdid, cd->cr));
+ call_desc[i].cdid = CDID_UNUSED;
+ break;
+ }
+ }
+
+ if(i == N_CALL_DESC)
+ panic("freecd_by_cd: ERROR, cd not found, cr = %d\n", cd->cr);
+
+ splx(x);
+}
+
+/*---------------------------------------------------------------------------*
+ * return pointer to calldescriptor by giving the calldescriptor id
+ * ----------------------------------------------------------------
+ * lookup a calldescriptor in the calldescriptor array by looking
+ * at the cdid field. return pointer to calldescriptor if found,
+ * else return NULL if not found.
+ *---------------------------------------------------------------------------*/
+call_desc_t *
+cd_by_cdid(unsigned int cdid)
+{
+ int i;
+
+ for(i=0; i < N_CALL_DESC; i++)
+ {
+ if(call_desc[i].cdid == cdid)
+ {
+ DBGL4(L4_MSG, "cd_by_cdid", ("found cdid - index=%d cdid=%u cr=%d\n",
+ i, call_desc[i].cdid, call_desc[i].cr));
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ init_callout(&call_desc[i]);
+#endif
+ return(&(call_desc[i]));
+ }
+ }
+ return(NULL);
+}
+
+/*---------------------------------------------------------------------------*
+ * search calldescriptor
+ * ---------------------
+ * This routine searches for the calldescriptor for a passive controller
+ * given by unit number, callreference and callreference flag.
+ * It returns a pointer to the calldescriptor if found, else a NULL.
+ *---------------------------------------------------------------------------*/
+call_desc_t *
+cd_by_unitcr(int unit, int cr, int crf)
+{
+ int i;
+
+ for(i=0; i < N_CALL_DESC; i++)
+ {
+ if((call_desc[i].cdid != CDID_UNUSED) &&
+ (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) &&
+ (ctrl_desc[call_desc[i].controller].unit == unit) &&
+ (call_desc[i].cr == cr) &&
+ (call_desc[i].crflag == crf) )
+ {
+ DBGL4(L4_MSG, "cd_by_unitcr", ("found cd, index=%d cdid=%u cr=%d\n",
+ i, call_desc[i].cdid, call_desc[i].cr));
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ init_callout(&call_desc[i]);
+#endif
+ return(&(call_desc[i]));
+ }
+ }
+ return(NULL);
+}
+
+/*---------------------------------------------------------------------------*
+ * generate 7 bit "random" number used for outgoing Call Reference
+ *---------------------------------------------------------------------------*/
+unsigned char
+get_rand_cr(int unit)
+{
+ register int i, j;
+ static u_char val, retval;
+ static int called = 42;
+
+ val += ++called;
+
+ for(i=0; i < 50 ; i++, val++)
+ {
+ int found = 1;
+
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ read_random((char *)&val, sizeof(val));
+#else
+ val |= unit+i;
+ val <<= i;
+ val ^= (time.tv_sec >> 8) ^ time.tv_usec;
+ val <<= i;
+ val ^= time.tv_sec ^ (time.tv_usec >> 8);
+#endif
+
+ retval = val & 0x7f;
+
+ if(retval == 0 || retval == 0x7f)
+ continue;
+
+ for(j=0; j < N_CALL_DESC; j++)
+ {
+ if( (call_desc[j].cdid != CDID_UNUSED) &&
+ (call_desc[j].cr == retval) )
+ {
+ found = 0;
+ break;
+ }
+ }
+
+ if(found)
+ return(retval);
+ }
+ return(0); /* XXX */
+}
+
+/*---------------------------------------------------------------------------*
+ * initialize the callout handles for FreeBSD-current 3.0
+ *---------------------------------------------------------------------------*/
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+void
+init_callout(call_desc_t *cd)
+{
+ if(cd->callouts_inited == 0)
+ {
+ callout_handle_init(&cd->idle_timeout_handle);
+ callout_handle_init(&cd->T303_callout);
+ callout_handle_init(&cd->T305_callout);
+ callout_handle_init(&cd->T308_callout);
+ callout_handle_init(&cd->T309_callout);
+ callout_handle_init(&cd->T310_callout);
+ callout_handle_init(&cd->T313_callout);
+ callout_handle_init(&cd->T400_callout);
+ cd->callouts_inited = 1;
+ }
+}
+#endif
+
+/*---------------------------------------------------------------------------*
+ * daemon is attached
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_daemon_attached(void)
+{
+ int i;
+
+ int x = SPLI4B();
+
+ for(i=0; i < nctrl; i++)
+ {
+/*XXX*/ if(ctrl_desc[i].ctrl_type == CTRL_PASSIVE)
+ {
+ DBGL4(L4_MSG, "i4b_l4_daemon_attached", ("CMR_DOPEN sent to unit %d\n", ctrl_desc[i].unit));
+
+ (*ctrl_desc[i].N_MGMT_COMMAND)(ctrl_desc[i].unit, CMR_DOPEN, 0);
+ }
+ }
+ splx(x);
+}
+
+/*---------------------------------------------------------------------------*
+ * daemon is detached
+ *---------------------------------------------------------------------------*/
+void
+i4b_l4_daemon_detached(void)
+{
+ int i;
+
+ int x = SPLI4B();
+
+ for(i=0; i < nctrl; i++)
+ {
+/*XXX*/ if(ctrl_desc[i].ctrl_type == CTRL_PASSIVE)
+ {
+ DBGL4(L4_MSG, "i4b_l4_daemon_detached", ("CMR_DCLOSE sent to unit %d\n", ctrl_desc[i].unit));
+
+ (*ctrl_desc[i].N_MGMT_COMMAND)(ctrl_desc[i].unit, CMR_DCLOSE, 0);
+ }
+ }
+ splx(x);
+}
+
+#ifdef I4B_CD_DEBUG_PRINT
+
+extern char *print_l3state(call_desc_t *cd);
+
+void i4b_print_cdp(call_desc_t *cdp);
+void i4b_print_cdx(int index);
+void i4b_print_cda(void);
+void i4b_print_cdaa(void);
+
+/*---------------------------------------------------------------------------*
+ * print a call descriptor by cd-pointer
+ *---------------------------------------------------------------------------*/
+void
+i4b_print_cdp(call_desc_t *cdp)
+{
+ if((cdp > &(call_desc[N_CALL_DESC])) || (cdp < &(call_desc[0])))
+ {
+ printf("i4b_print_cd: cdp out of range!\n");
+ return;
+ }
+
+ printf("i4b_print_cd: printing call descriptor %d at 0x%lx:\n", cdp - (&(call_desc[0])), (unsigned long)cdp);
+
+ printf(" cdid = %d\n", cdp->cdid);
+ printf(" controller = %d (u=%d, dl=%d, b1=%d, b2=%d)\n",
+ cdp->controller,
+ ctrl_desc[cdp->controller].unit,
+ ctrl_desc[cdp->controller].dl_est,
+ ctrl_desc[cdp->controller].bch_state[CHAN_B1],
+ ctrl_desc[cdp->controller].bch_state[CHAN_B2]);
+ printf(" cr = 0x%02x\n", cdp->cr);
+ printf(" crflag = %d\n", cdp->crflag);
+ printf(" channelid = %d\n", cdp->channelid);
+ printf(" bprot = %d\n", cdp->bprot);
+ printf(" driver = %d\n", cdp->driver);
+ printf(" driver_unit = %d\n", cdp->driver_unit);
+ printf(" call_state = %d\n", cdp->call_state);
+ printf(" Q931state = %s\n", print_l3state(cdp));
+ printf(" event = %d\n", cdp->event);
+ printf(" response = %d\n", cdp->response);
+ printf(" T303 = %d\n", cdp->T303);
+ printf("T303_first_to = %d\n", cdp->T303_first_to);
+ printf(" T305 = %d\n", cdp->T305);
+ printf(" T308 = %d\n", cdp->T308);
+ printf("T308_first_to = %d\n", cdp->T308_first_to);
+ printf(" T309 = %d\n", cdp->T309);
+ printf(" T310 = %d\n", cdp->T310);
+ printf(" T313 = %d\n", cdp->T313);
+ printf(" T400 = %d\n", cdp->T400);
+ printf(" dir = %s\n", cdp->dir == DIR_OUTGOING ? "out" : "in");
+}
+
+/*---------------------------------------------------------------------------*
+ * print a call descriptor by index
+ *---------------------------------------------------------------------------*/
+void
+i4b_print_cdx(int index)
+{
+ if(index >= N_CALL_DESC)
+ {
+ printf("i4b_print_cdx: index %d >= N_CALL_DESC %d\n", index, N_CALL_DESC);
+ return;
+ }
+ i4b_print_cdp(&(call_desc[index]));
+}
+
+/*---------------------------------------------------------------------------*
+ * print all call descriptors
+ *---------------------------------------------------------------------------*/
+void
+i4b_print_cda(void)
+{
+ int i;
+
+ for(i=0; i < N_CALL_DESC; i++)
+ {
+ i4b_print_cdp(&(call_desc[i]));
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * print all active call descriptors
+ *---------------------------------------------------------------------------*/
+void
+i4b_print_cdaa(void)
+{
+ int i;
+
+ for(i=0; i < N_CALL_DESC; i++)
+ {
+ if(call_desc[i].cdid != CDID_UNUSED)
+ {
+ i4b_print_cdp(&(call_desc[i]));
+ }
+ }
+}
+
+#endif /* I4B_CD_DEBUG_PRINT */
+
+#endif /* NI4BQ931 > 0 */
diff --git a/sys/i4b/layer4/i4b_l4timer.c b/sys/i4b/layer4/i4b_l4timer.c
new file mode 100644
index 0000000..7a38e13
--- /dev/null
+++ b/sys/i4b/layer4/i4b_l4timer.c
@@ -0,0 +1,110 @@
+/*
+ * 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_l4timer.c - timer and timeout handling for layer 4
+ * --------------------------------------------------------
+ *
+ * $Id: i4b_l4timer.c,v 1.10 1998/12/05 18:05:53 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:36:07 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "i4b.h"
+
+#if NI4B > 0
+
+#include <sys/param.h>
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+#include <sys/ioccom.h>
+#else
+#include <sys/ioctl.h>
+#endif
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#ifdef __FreeBSD__
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#else
+#include <i4b/i4b_debug.h>
+#include <i4b/i4b_ioctl.h>
+#endif
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l3l4.h>
+#include <i4b/include/i4b_mbuf.h>
+
+#include <i4b/layer4/i4b_l4.h>
+
+/*---------------------------------------------------------------------------*
+ * timer T400 timeout function
+ *---------------------------------------------------------------------------*/
+static void
+T400_timeout(call_desc_t *cd)
+{
+ DBGL4(L4_ERR, "T400_timeout", ("cr = %d\n", cd->cr));
+}
+
+/*---------------------------------------------------------------------------*
+ * timer T400 start
+ *---------------------------------------------------------------------------*/
+void
+T400_start(call_desc_t *cd)
+{
+ DBGL4(L4_MSG, "T400_start", ("cr = %d\n", cd->cr));
+
+ cd->T400 = TIMER_ACTIVE;
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ cd->T400_callout = timeout((TIMEOUT_FUNC_T)T400_timeout, (void *)cd, T400DEF);
+#else
+ timeout((TIMEOUT_FUNC_T)T400_timeout, (void *)cd, T400DEF);
+#endif
+}
+
+/*---------------------------------------------------------------------------*
+ * timer T400 stop
+ *---------------------------------------------------------------------------*/
+void
+T400_stop(call_desc_t *cd)
+{
+ DBGL4(L4_MSG, "T400_stop", ("cr = %d\n", cd->cr));
+
+ if(cd->T400 == TIMER_ACTIVE)
+ {
+ cd->T400 = TIMER_IDLE;
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
+ untimeout((TIMEOUT_FUNC_T)T400_timeout, (void *)cd, cd->T400_callout);
+#else
+ untimeout((TIMEOUT_FUNC_T)T400_timeout, (void *)cd);
+#endif
+ }
+}
+
+#endif /* NI4B > 0 */
OpenPOWER on IntegriCloud