From 6a7a858eb20717cde175d9eb1b2d25ef83dd0bac Mon Sep 17 00:00:00 2001 From: pooka Date: Thu, 25 Sep 2003 15:34:38 +0000 Subject: [PATCH] Add a support layer for the ISDN CAPI (http://www.capi.org/), which should make it pretty simple to write drivers for cards which conform to CAPI. This code was originally written by Juha-Matti Liukkonen of Cubical Solutions Ltd. for FreeBSD, and was now adapted to NetBSD by myself for the same company. --- sys/netisdn/i4b_capi.h | 136 +++++ sys/netisdn/i4b_capi_l4if.c | 424 ++++++++++++++++ sys/netisdn/i4b_capi_llif.c | 161 ++++++ sys/netisdn/i4b_capi_msgs.c | 977 ++++++++++++++++++++++++++++++++++++ sys/netisdn/i4b_capi_msgs.h | 382 ++++++++++++++ 5 files changed, 2080 insertions(+) create mode 100644 sys/netisdn/i4b_capi.h create mode 100644 sys/netisdn/i4b_capi_l4if.c create mode 100644 sys/netisdn/i4b_capi_llif.c create mode 100644 sys/netisdn/i4b_capi_msgs.c create mode 100644 sys/netisdn/i4b_capi_msgs.h diff --git a/sys/netisdn/i4b_capi.h b/sys/netisdn/i4b_capi.h new file mode 100644 index 000000000000..fe02d4d1c8be --- /dev/null +++ b/sys/netisdn/i4b_capi.h @@ -0,0 +1,136 @@ +/* $NetBSD: i4b_capi.h,v 1.1 2003/09/25 15:34:38 pooka Exp $ */ + +/* + * Copyright (c) 2001-2003 Cubical Solutions Ltd. 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. + * + * capi/capi.h The CAPI device interface. + * + * $FreeBSD: src/sys/i4b/capi/capi.h,v 1.1 2001/05/25 08:39:31 hm Exp $ + */ + +#ifndef _I4B_CAPI_H_ +#define _I4B_CAPI_H_ + +/* +// CAPI driver context: B channels and controller softcs. +*/ + +#define INVALID -1 + +enum capi_b_state { + B_FREE, /* 0: channel free, ncci invalid */ + B_CONNECT_CONF, /* 1: wait for CONNECT_CONF */ + B_CONNECT_IND, /* 2: IND got, wait for appl RESP */ + B_CONNECT_ACTIVE_IND, /* 3: wait for CONNECT_ACTIVE_IND */ + B_CONNECT_B3_CONF, /* 4: wait for CONNECT_B3_CONF */ + B_CONNECT_B3_IND, /* 5: wait for CONNECT_B3_IND */ + B_CONNECT_B3_ACTIVE_IND, /* 6: wait for CONNECT_B3_ACTIVE_IND */ + B_CONNECTED, /* 7: channel connected & in use */ + B_DISCONNECT_CONF, /* 8: wait for DISCONNECT_CONF */ + B_DISCONNECT_B3_CONF, /* 9: wait for DISCONNECT_B3_CONF */ + B_DISCONNECT_IND, /* 10: wait for DISCONNECT_IND */ +}; + +typedef struct capi_bchan +{ + /* Channel state */ + + int ncci; +#define CAPI_CTRL_MASK 0x000000ff +#define CAPI_PLCI_MASK 0x0000ffff +#define CAPI_NCCI_MASK 0xffff0000 + u_int16_t msgid; + int busy; + enum capi_b_state state; + + struct ifqueue tx_queue; + struct ifqueue rx_queue; + int rxcount; + int txcount; + + /* The rest is needed for i4b integration */ + int bprot; + int cdid; + + struct mbuf *in_mbuf; + isdn_link_t capi_isdn_linktab; + + const struct isdn_l4_driver_functions *l4_driver; + void *l4_driver_softc; +} capi_bchan_t; + +enum capi_c_state { + C_DOWN, /* controller uninitialized */ + C_READY, /* controller initialized but not listening */ + C_UP, /* controller listening */ +}; + +typedef struct capi_softc { + int sc_unit; /* index in capi_sc[] */ + int card_type; /* CARD_TYPEC_xxx, filled by ll driver */ + int sc_nbch; /* number of b channels on this controller */ + int sc_enabled; /* is daemon connected TRUE/FALSE */ + int sc_msgid; /* next CAPI message id */ + int capi_bri; /* bri identifier */ + char sc_profile[64];/* CAPI profile data */ + enum capi_c_state sc_state; + + capi_bchan_t sc_bchan[MAX_BCHAN]; + + /* Link layer driver context holder and methods */ + void *ctx; + + int (*load)(struct capi_softc *, int, u_int8_t *); + int (*reg_appl)(struct capi_softc *, int, int); + int (*rel_appl)(struct capi_softc *, int); + int (*send)(struct capi_softc *, struct mbuf *); +} capi_softc_t; + +extern int ncapi; + +#define CARD_TYPEC_CAPI_UNK 0 +#define CARD_TYPEC_AVM_T1_PCI 1 +#define CARD_TYPEC_AVM_B1_PCI 2 +#define CARD_TYPEC_AVM_B1_ISA 3 + +/* +// CAPI upcalls for the link layer. +*/ + +#define I4BCAPI_APPLID 1 + +extern int capi_ll_attach(capi_softc_t *, const char *, const char *); +extern int capi_ll_control(capi_softc_t *, int op, int arg); +extern int capi_ll_detach(capi_softc_t *); + +#define CAPI_CTRL_READY 0 /* ctrl ready, value=TRUE/FALSE */ +#define CAPI_CTRL_PROFILE 1 /* set CAPI profile */ +#define CAPI_CTRL_NEW_NCCI 2 /* new ncci value, assign bchan */ +#define CAPI_CTRL_FREE_NCCI 3 /* free ncci value, clear bchan */ + +extern int capi_ll_receive(capi_softc_t *, struct mbuf *); + +extern int capi_start_tx(void *, int bchan); + +#endif /* _I4B_CAPI_H_ */ diff --git a/sys/netisdn/i4b_capi_l4if.c b/sys/netisdn/i4b_capi_l4if.c new file mode 100644 index 000000000000..74d51ce5d609 --- /dev/null +++ b/sys/netisdn/i4b_capi_l4if.c @@ -0,0 +1,424 @@ +/* $NetBSD: i4b_capi_l4if.c,v 1.1 2003/09/25 15:34:38 pooka Exp $ */ + +/* + * Copyright (c) 2001-2003 Cubical Solutions Ltd. 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. + * + * capi/capi_l4if.c The CAPI i4b L4/device interface. + * + * $FreeBSD: src/sys/i4b/capi/capi_l4if.c,v 1.4 2002/04/04 21:03:20 jhb Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void n_connect_request(call_desc_t *); +static void n_connect_response(call_desc_t *, int response, int cause); +static void n_disconnect_request(call_desc_t *, int cause); +static void n_alert_request(call_desc_t *); +static void n_mgmt_command(struct isdn_l3_driver *, int cmd, void *parm); +static int n_download(void *, int, struct isdn_dr_prot *); + +static int ncapi = 0; + +/* +// i4b_capi_{ret,set}_linktab +// i4b driver glue. +// +// i4b_capi_bch_config +// Called by i4b driver to flush + {en,dis}able a channel. +// +// i4b_capi_bch_start_tx +// Called by i4b driver to transmit a queued mbuf. +// +// i4b_capi_bch_stat +// Called by i4b driver to obtain statistics information. +*/ + +static isdn_link_t * +i4b_capi_ret_linktab(void *token, int channel) +{ + capi_softc_t *sc = token; + + return &sc->sc_bchan[channel].capi_isdn_linktab; +} + +static void +i4b_capi_set_link(void *token, int channel, + const struct isdn_l4_driver_functions *l4_driver, void *l4_inst) +{ + capi_softc_t *sc = token; + + sc->sc_bchan[channel].l4_driver = l4_driver; + sc->sc_bchan[channel].l4_driver_softc = l4_inst; +} + +static void +i4b_capi_bch_config(void *token, int chan, int bprot, int activate) +{ + capi_softc_t *sc = token; + + i4b_Bcleanifq(&sc->sc_bchan[chan].tx_queue); + sc->sc_bchan[chan].tx_queue.ifq_maxlen = IFQ_MAXLEN; + sc->sc_bchan[chan].txcount = 0; + + /* The telephony drivers use rx_queue for receive. */ + i4b_Bcleanifq(&sc->sc_bchan[chan].rx_queue); + sc->sc_bchan[chan].rx_queue.ifq_maxlen = IFQ_MAXLEN; + sc->sc_bchan[chan].rxcount = 0; + + /* HDLC frames are put to in_mbuf */ + i4b_Bfreembuf(sc->sc_bchan[chan].in_mbuf); + sc->sc_bchan[chan].in_mbuf = NULL; + + /* Because of the difference, we need to remember the protocol. */ + sc->sc_bchan[chan].bprot = bprot; + sc->sc_bchan[chan].busy = 0; +} + +static void +i4b_capi_bch_start_tx(void *token, int chan) +{ + capi_softc_t *sc = token; + int s; + + s = splnet(); + + if (sc->sc_bchan[chan].state != B_CONNECTED) { + splx(s); + printf("capi%d: start_tx on unconnected channel\n", sc->sc_unit); + return; + } + + if (sc->sc_bchan[chan].busy) { + splx(s); + return; + } + + capi_start_tx(sc, chan); + + splx(s); +} + +static void +i4b_capi_bch_stat(void *token, int chan, bchan_statistics_t *bsp) +{ + capi_softc_t *sc = token; + int s = splnet(); + + bsp->outbytes = sc->sc_bchan[chan].txcount; + bsp->inbytes = sc->sc_bchan[chan].rxcount; + + sc->sc_bchan[chan].txcount = 0; + sc->sc_bchan[chan].rxcount = 0; + + splx(s); +} + +int capi_start_tx(void *token, int chan) +{ + capi_softc_t *sc = token; + struct mbuf *m_b3; + int sent = 0; + + IF_DEQUEUE(&sc->sc_bchan[chan].tx_queue, m_b3); + while (m_b3) { + struct mbuf *m = m_b3->m_next; + + sc->sc_bchan[chan].txcount += m_b3->m_len; + capi_data_b3_req(sc, chan, m_b3); + sent++; + + m_b3 = m; + } + + if (sc->sc_bchan[chan].l4_driver) { + capi_bchan_t *bch = &sc->sc_bchan[chan]; + + /* Notify i4b driver of activity, and if the queue is drained. */ + if (sent) + (*bch->l4_driver->bch_activity)(bch->l4_driver_softc, ACT_TX); + + if (IF_QEMPTY(&bch->tx_queue)) + (*bch->l4_driver->bch_tx_queue_empty)(bch->l4_driver_softc); + } + + return sent; +} + +static const struct isdn_l4_bchannel_functions +capi_l4_driver = { + i4b_capi_bch_config, + i4b_capi_bch_start_tx, + i4b_capi_bch_stat +}; + +/* +// n_mgmt_command +// i4b L4 management command. +*/ + +static void +n_mgmt_command(struct isdn_l3_driver *l3, int op, void *arg) +{ + capi_softc_t *sc = l3->l1_token; + +#if 0 + printf("capi%d: mgmt command %d\n", sc->sc_unit, op); +#endif + + switch(op) { + case CMR_DOPEN: + sc->sc_enabled = 1; + break; + + case CMR_DCLOSE: + sc->sc_enabled = 0; + break; + + case CMR_SETTRACE: + break; + + default: + break; + } +} + +/* +// n_connect_request +// i4b L4 wants to connect. We assign a B channel to the call, +// send a CAPI_CONNECT_REQ, and set the channel to B_CONNECT_CONF. +*/ + +static void +n_connect_request(call_desc_t *cd) +{ + capi_softc_t *sc; + int bch, s; + + sc = cd->l3drv->l1_token; + bch = cd->channelid; + + s = splnet(); + + if ((bch < 0) || (bch >= sc->sc_nbch)) + for (bch = 0; bch < sc->sc_nbch; bch++) + if (sc->sc_bchan[bch].state == B_FREE) + break; + + if (bch == sc->sc_nbch) { + splx(s); + printf("capi%d: no free B channel\n", sc->sc_unit); + return; + } + + cd->channelid = bch; + + capi_connect_req(sc, cd); + splx(s); +} + +/* +// n_connect_response +// i4b L4 answers a call. We send a CONNECT_RESP with the proper +// Reject code, and set the channel to B_CONNECT_B3_IND or B_FREE, +// depending whether we answer or not. +*/ + +static void +n_connect_response(call_desc_t *cd, int response, int cause) +{ + capi_softc_t *sc; + int bch, s; + + sc = cd->l3drv->l1_token; + bch = cd->channelid; + + T400_stop(cd); + + cd->response = response; + cd->cause_out = cause; + + s = splnet(); + capi_connect_resp(sc, cd); + splx(s); +} + +/* +// n_disconnect_request +// i4b L4 wants to disconnect. We send a DISCONNECT_REQ and +// set the channel to B_DISCONNECT_CONF. +*/ + +static void +n_disconnect_request(call_desc_t *cd, int cause) +{ + capi_softc_t *sc; + int bch, s; + + sc = cd->l3drv->l1_token; + bch = cd->channelid; + + cd->cause_out = cause; + + s = splnet(); + capi_disconnect_req(sc, cd); + splx(s); +} + +/* +// n_alert_request +// i4b L4 wants to alert an incoming call. We send ALERT_REQ. +*/ + +static void +n_alert_request(call_desc_t *cd) +{ + capi_softc_t *sc; + int s; + + sc = cd->l3drv->l1_token; + + s = splnet(); + capi_alert_req(sc, cd); + splx(s); +} + +/* +// n_download +// L4 -> firmware download +*/ + +static int +n_download(void *token, int numprotos, struct isdn_dr_prot *protocols) +{ + capi_softc_t *sc = token; + + if (sc->load) { + (*sc->load)(sc, protocols[0].bytecount, + protocols[0].microcode); + return(0); + } + + return(ENXIO); +} + +static const struct isdn_l3_driver_functions +capi_l3_functions = { + i4b_capi_ret_linktab, + i4b_capi_set_link, + n_connect_request, + n_connect_response, + n_disconnect_request, + n_alert_request, + n_download, + NULL, + n_mgmt_command +}; + +/* +// capi_ll_attach +// Called by a link layer driver at boot time. +*/ + +int +capi_ll_attach(capi_softc_t *sc, const char *devname, const char *cardname) +{ + struct isdn_l3_driver *l3drv; + int i; + + /* Unit state */ + + sc->sc_enabled = 0; + sc->sc_state = C_DOWN; + sc->sc_msgid = 0; + + for (i = 0; i < sc->sc_nbch; i++) { + sc->sc_bchan[i].ncci = INVALID; + sc->sc_bchan[i].msgid = 0; + sc->sc_bchan[i].busy = 0; + sc->sc_bchan[i].state = B_FREE; + + memset(&sc->sc_bchan[i].tx_queue, 0, sizeof(struct ifqueue)); + memset(&sc->sc_bchan[i].rx_queue, 0, sizeof(struct ifqueue)); + sc->sc_bchan[i].tx_queue.ifq_maxlen = IFQ_MAXLEN; + sc->sc_bchan[i].rx_queue.ifq_maxlen = IFQ_MAXLEN; + + sc->sc_bchan[i].txcount = 0; + sc->sc_bchan[i].rxcount = 0; + + sc->sc_bchan[i].cdid = CDID_UNUSED; + sc->sc_bchan[i].bprot = BPROT_NONE; + sc->sc_bchan[i].in_mbuf = NULL; + + sc->sc_bchan[i].capi_isdn_linktab.l1token = sc; + sc->sc_bchan[i].capi_isdn_linktab.channel = i; + sc->sc_bchan[i].capi_isdn_linktab.bchannel_driver = &capi_l4_driver; + sc->sc_bchan[i].capi_isdn_linktab.tx_queue = &sc->sc_bchan[i].tx_queue; + sc->sc_bchan[i].capi_isdn_linktab.rx_queue = &sc->sc_bchan[i].rx_queue; + sc->sc_bchan[i].capi_isdn_linktab.rx_mbuf = &sc->sc_bchan[i].in_mbuf; + } + + l3drv = isdn_attach_bri(devname, cardname, sc, &capi_l3_functions); + + l3drv->tei = -1; + l3drv->dl_est = DL_DOWN; + l3drv->nbch = sc->sc_nbch; + + sc->sc_unit = ncapi++; + sc->capi_bri = l3drv->bri; + + isdn_bri_ready(l3drv->bri); + + printf("capi%d: card type %d attached\n", sc->sc_unit, sc->card_type); + + return(0); +} + + +/* +// capi_ll_detach +*/ + +int +capi_ll_detach(capi_softc_t *sc) +{ + + /* TODO */ + return(0); +} diff --git a/sys/netisdn/i4b_capi_llif.c b/sys/netisdn/i4b_capi_llif.c new file mode 100644 index 000000000000..cc3896d422a0 --- /dev/null +++ b/sys/netisdn/i4b_capi_llif.c @@ -0,0 +1,161 @@ +/* $NetBSD: i4b_capi_llif.c,v 1.1 2003/09/25 15:34:38 pooka Exp $ */ + +/* + * Copyright (c) 2001 Cubical Solutions Ltd. 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. + * + * capi/capi_llif.c The i4b CAPI link layer interface. + * + * $FreeBSD: src/sys/i4b/capi/capi_llif.c,v 1.1 2001/05/25 08:39:31 hm Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +// capi_ll_control +// CAPI link layer control routine. Called by a link layer +// driver when its state changes. +*/ + +int +capi_ll_control(capi_softc_t *sc, int op, int arg) +{ + switch (op) { + case CAPI_CTRL_READY: + if (arg) { + sc->sc_state = C_READY; + + /* + * Register our CAPI ApplId and send CAPI_LISTEN_REQ + * with CIP Mask value 1 (match all). + */ + + sc->reg_appl(sc, I4BCAPI_APPLID, sc->sc_nbch); + capi_listen_req(sc, 0x10007); + + } else { + sc->sc_state = C_DOWN; + /* XXX go through cds and notify L4 of pdeact? XXX */ + } + break; + + case CAPI_CTRL_PROFILE: + bcopy((char*) arg, &sc->sc_profile, sizeof(sc->sc_profile)); + break; + + case CAPI_CTRL_NEW_NCCI: + case CAPI_CTRL_FREE_NCCI: + /* We ignore the controller's NCCI notifications. */ + break; + + default: + printf("capi%d: unknown control %d\n", sc->sc_unit, op); + } + + return 0; +} + +/* +// i4b_capi_handlers +// Array of message-handler pairs used to dispatch CAPI +// messages sent to I4BCAPI_APPLID. +*/ + +static struct capi_cmdtab { + u_int16_t cmd; + void (*handler)(capi_softc_t *, struct mbuf *); +} i4b_capi_handlers[] = { + { CAPI_LISTEN_CONF, capi_listen_conf }, + { CAPI_INFO_IND, capi_info_ind }, + { CAPI_ALERT_CONF, capi_alert_conf }, + { CAPI_CONNECT_CONF, capi_connect_conf }, + { CAPI_CONNECT_IND, capi_connect_ind }, + { CAPI_CONNECT_ACTIVE_IND, capi_connect_active_ind }, + { CAPI_CONNECT_B3_CONF, capi_connect_b3_conf }, + { CAPI_CONNECT_B3_IND, capi_connect_b3_ind }, + { CAPI_CONNECT_B3_ACTIVE_IND, capi_connect_b3_active_ind }, + { CAPI_DATA_B3_CONF, capi_data_b3_conf }, + { CAPI_DATA_B3_IND, capi_data_b3_ind }, + { CAPI_DISCONNECT_B3_IND, capi_disconnect_b3_ind }, + { CAPI_DISCONNECT_CONF, capi_disconnect_conf }, + { CAPI_DISCONNECT_IND, capi_disconnect_ind }, + { 0, 0 } +}; + +/* +// capi_ll_receive +// CAPI link layer receive upcall. Called by a link layer +// driver to dispatch incoming CAPI messages. +*/ + +int +capi_ll_receive(capi_softc_t *sc, struct mbuf *m) +{ + u_int8_t *p = mtod(m, u_int8_t*); + u_int16_t len, applid, msgid, cmd; + + capimsg_getu16(p + 0, &len); + capimsg_getu16(p + 2, &applid); + capimsg_getu16(p + 4, &cmd); + capimsg_getu16(p + 6, &msgid); + +#if 0 + printf("capi%d: ll_receive hdr %04x %04x %04x %04x\n", sc->sc_unit, + len, applid, cmd, msgid); +#endif + + if (applid == I4BCAPI_APPLID) { + struct capi_cmdtab *e; + for (e = i4b_capi_handlers; e->cmd && e->cmd != cmd; e++); + if (e->cmd) (*e->handler)(sc, m); + else printf("capi%d: unknown message %04x\n", sc->sc_unit, cmd); + + } else { + /* XXX we could handle arbitrary ApplIds here XXX */ + printf("capi%d: message %04x for unknown applid %d\n", sc->sc_unit, + cmd, applid); + } + + if (m->m_next) { + i4b_Bfreembuf(m->m_next); + m->m_next = NULL; + } + i4b_Dfreembuf(m); + return(0); +} diff --git a/sys/netisdn/i4b_capi_msgs.c b/sys/netisdn/i4b_capi_msgs.c new file mode 100644 index 000000000000..ec6f8f20ca2d --- /dev/null +++ b/sys/netisdn/i4b_capi_msgs.c @@ -0,0 +1,977 @@ +/* $NetBSD: i4b_capi_msgs.c,v 1.1 2003/09/25 15:34:38 pooka Exp $ */ + +/* + * Copyright (c) 2001-2003 Cubical Solutions Ltd. 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. + * + * capi/capi_msgs.c The CAPI i4b message handlers. + * + * $FreeBSD: src/sys/i4b/capi/capi_msgs.c,v 1.2 2001/10/21 08:51:54 hm Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +// Administrative messages: +// ------------------------ +*/ + +void capi_listen_req(capi_softc_t *sc, u_int32_t CIP) +{ + struct mbuf *m = i4b_Dgetmbuf(8 + 18); + u_int8_t *msg; + u_int16_t msgid; + + if (!m) { + printf("capi%d: can't get mbuf for listen_req\n", sc->sc_unit); + return; + } + + msgid = sc->sc_msgid++; + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, I4BCAPI_APPLID); + msg = capimsg_setu16(msg, CAPI_LISTEN_REQ); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, 1); /* Controller */ + msg = capimsg_setu32(msg, 0); /* Info mask */ + msg = capimsg_setu32(msg, CIP); + msg = capimsg_setu32(msg, 0); + msg = capimsg_setu8(msg, 0); + msg = capimsg_setu8(msg, 0); + + sc->send(sc, m); +} + +void capi_listen_conf(capi_softc_t *sc, struct mbuf *m_in) +{ + struct isdn_l3_driver *l3drv; + u_int8_t *msg = mtod(m_in, u_int8_t*); + u_int16_t Info; + + capimsg_getu16(msg + 12, &Info); + + if (Info == 0) { + /* We are now listening. */ + + sc->sc_state = C_UP; + l3drv = isdn_find_l3_by_bri(sc->capi_bri); + l3drv->dl_est = DL_UP; + + i4b_l4_l12stat(l3drv, 1, 1); + i4b_l4_l12stat(l3drv, 2, 1); + + } else { + /* XXX sc->sc_state = C_DOWN ? XXX */ + printf("capi%d: can't listen, info=%04x\n", sc->sc_unit, Info); + } +} + +void capi_info_ind(capi_softc_t *sc, struct mbuf *m_in) +{ + struct mbuf *m = i4b_Dgetmbuf(8 + 4); + u_int8_t *msg = mtod(m_in, u_int8_t*); + u_int16_t applid, msgid; + u_int32_t PLCI; + + if (!m) { + printf("capi%d: can't get mbuf for info_resp\n", sc->sc_unit); + return; + } + + msg = capimsg_getu16(msg + 2, &applid); + msg = capimsg_getu16(msg + 2, &msgid); + msg = capimsg_getu32(msg, &PLCI); + + /* i4b_l4_info_ind() */ + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, applid); + msg = capimsg_setu16(msg, CAPI_INFO_RESP); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, PLCI); + + sc->send(sc, m); +} + +void capi_alert_req(capi_softc_t *sc, call_desc_t *cd) +{ + struct mbuf *m = i4b_Dgetmbuf(8 + 5); + u_int8_t *msg; + u_int16_t msgid; + u_int32_t PLCI; + + if (!m) { + printf("capi%d: can't get mbuf for alert_req\n", sc->sc_unit); + return; + } + + msgid = sc->sc_bchan[cd->channelid].msgid = sc->sc_msgid++; + PLCI = (sc->sc_bchan[cd->channelid].ncci & CAPI_PLCI_MASK); + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, I4BCAPI_APPLID); + msg = capimsg_setu16(msg, CAPI_ALERT_REQ); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, PLCI); + msg = capimsg_setu8(msg, 0); + + sc->send(sc, m); +} + +void capi_alert_conf(capi_softc_t *sc, struct mbuf *m_in) +{ + u_int8_t *msg = mtod(m_in, u_int8_t*); + u_int16_t Info; + + msg = capimsg_getu16(msg + 12, &Info); + + if (Info) { + printf("capi%d: can't alert, info=%04x\n", sc->sc_unit, Info); + } +} + +/* +// Outgoing call setup: +// -------------------- +// +// CAPI_CONNECT_REQ --> +// <-- CAPI_CONNECT_CONF +// (notify Layer 4) +// <-- CAPI_CONNECT_ACTIVE_IND +// CAPI_CONNECT_ACTIVE_RESP --> +// CAPI_CONNECT_B3_REQ --> +// <-- CAPI_CONNECT_B3_CONF +// <-- CAPI_CONNECT_B3_ACTIVE_IND +// CAPI_CONNECT_B3_ACTIVE_RESP --> +// (notify Layer 4) +*/ + +void capi_connect_req(capi_softc_t *sc, call_desc_t *cd) +{ + struct isdn_l3_driver *l3drv; + struct mbuf *m; + u_int8_t *msg; + u_int16_t msgid; + int slen = strlen(cd->src_telno); + int dlen = strlen(cd->dst_telno); + + m = i4b_Dgetmbuf(8 + 27 + slen + dlen); + if (!m) { + printf("capi%d: can't get mbuf for connect_req\n", sc->sc_unit); + return; + } + + l3drv = isdn_find_l3_by_bri(sc->capi_bri); + + cd->crflag = CRF_ORIG; + + sc->sc_bchan[cd->channelid].cdid = cd->cdid; + sc->sc_bchan[cd->channelid].bprot = cd->bprot; + sc->sc_bchan[cd->channelid].state = B_CONNECT_CONF; + msgid = sc->sc_bchan[cd->channelid].msgid = sc->sc_msgid++; + l3drv->bch_state[cd->channelid] = BCH_ST_RSVD; + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, I4BCAPI_APPLID); + msg = capimsg_setu16(msg, CAPI_CONNECT_REQ); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, 1); /* Controller */ + + switch (cd->bprot) { + case BPROT_NONE: + msg = capimsg_setu16(msg, 0x0010); /* Telephony */ + break; + + case BPROT_RHDLC: + msg = capimsg_setu16(msg, 0x0002); /* Unrestricted digital */ + break; + + default: + msg = capimsg_setu16(msg, 0x0002); /* Unrestricted digital */ + } + + msg = capimsg_setu8(msg, 1 + dlen); + msg = capimsg_setu8(msg, 0x80); + strncpy(msg, cd->dst_telno, dlen); + + msg = capimsg_setu8(msg + dlen, 2 + slen); + msg = capimsg_setu8(msg, 0x00); + msg = capimsg_setu8(msg, 0x80); /* Presentation and screening indicator */ + strncpy(msg, cd->src_telno, slen); + + msg = capimsg_setu8(msg + slen, 0); /* Called & */ + msg = capimsg_setu8(msg, 0); /* Calling party subaddress */ + + msg = capimsg_setu8(msg, 15); /* B protocol */ + if (cd->bprot == BPROT_NONE) + msg = capimsg_setu16(msg, 1); /* B1 protocol = transparent */ + else + msg = capimsg_setu16(msg, 0); /* B1 protocol = HDLC */ + msg = capimsg_setu16(msg, 1); /* B2 protocol = transparent */ + msg = capimsg_setu16(msg, 0); /* B3 protocol = transparent */ + msg = capimsg_setu8(msg, 0); /* B1 parameters */ + msg = capimsg_setu8(msg, 0); /* B2 parameters */ + msg = capimsg_setu8(msg, 0); /* B3 parameters */ + + msg = capimsg_setu8(msg, 0); /* Bearer Capability */ + msg = capimsg_setu8(msg, 0); /* Low Layer Compatibility */ + msg = capimsg_setu8(msg, 0); /* High Layer Compatibility */ + msg = capimsg_setu8(msg, 0); /* Additional Info */ + + sc->send(sc, m); +} + +void capi_connect_conf(capi_softc_t *sc, struct mbuf *m_in) +{ + u_int8_t *msg = mtod(m_in, u_int8_t*); + call_desc_t *cd; + u_int16_t msgid; + u_int32_t PLCI; + u_int16_t Info; + int bch; + + msg = capimsg_getu16(msg + 6, &msgid); + msg = capimsg_getu32(msg, &PLCI); + msg = capimsg_getu16(msg, &Info); + + for (bch = 0; bch < sc->sc_nbch; bch++) + if ((sc->sc_bchan[bch].state == B_CONNECT_CONF) && + (sc->sc_bchan[bch].msgid == msgid)) + break; + + if ((bch == sc->sc_nbch) || + (cd = cd_by_cdid(sc->sc_bchan[bch].cdid)) == NULL) { + printf("capi%d: can't find channel for connect_conf PLCI %x\n", + sc->sc_unit, PLCI); + return; + } + + if (Info == 0) { + sc->sc_bchan[bch].state = B_CONNECT_ACTIVE_IND; + sc->sc_bchan[bch].ncci = PLCI; + + i4b_l4_proceeding_ind(cd); + + } else { + struct isdn_l3_driver *l3drv; + + l3drv = isdn_find_l3_by_bri(sc->capi_bri); + SET_CAUSE_TV(cd->cause_out, CAUSET_I4B, CAUSE_I4B_L1ERROR); + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); + + sc->sc_bchan[bch].state = B_FREE; + + l3drv->bch_state[bch] = BCH_ST_FREE; + + printf("capi%d: can't connect out, info=%04x\n", sc->sc_unit, Info); + } +} + +void capi_connect_active_ind(capi_softc_t *sc, struct mbuf *m_in) +{ + struct mbuf *m = i4b_Dgetmbuf(8 + 4); + u_int8_t *msg = mtod(m_in, u_int8_t*); + call_desc_t *cd; + u_int16_t applid, msgid; + u_int32_t PLCI; + int bch; + + if (!m) { + printf("capi%d: can't get mbuf for active_ind\n", sc->sc_unit); + return; + } + + msg = capimsg_getu16(msg + 2, &applid); + msg = capimsg_getu16(msg + 2, &msgid); + msg = capimsg_getu32(msg, &PLCI); + + for (bch = 0; bch < sc->sc_nbch; bch++) + if ((sc->sc_bchan[bch].state == B_CONNECT_ACTIVE_IND) && + (sc->sc_bchan[bch].ncci == PLCI)) + break; + + if ((bch == sc->sc_nbch) || + (cd = cd_by_cdid(sc->sc_bchan[bch].cdid)) == NULL) { + printf("capi%d: can't find channel for active_resp, PLCI %x\n", + sc->sc_unit, PLCI); + return; + } + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, applid); + msg = capimsg_setu16(msg, CAPI_CONNECT_ACTIVE_RESP); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, PLCI); + + sc->send(sc, m); + + if (cd->crflag == CRF_ORIG) { + capi_connect_b3_req(sc, cd); + + } else { + sc->sc_bchan[bch].state = B_CONNECT_B3_IND; + } +} + +void capi_connect_b3_req(capi_softc_t *sc, call_desc_t *cd) +{ + struct mbuf *m = i4b_Dgetmbuf(8 + 5); + u_int8_t *msg; + u_int16_t msgid; + u_int32_t PLCI; + + if (!m) { + printf("capi%d: can't get mbuf for connect_b3_req\n", sc->sc_unit); + return; + } + + sc->sc_bchan[cd->channelid].state = B_CONNECT_B3_CONF; + msgid = sc->sc_bchan[cd->channelid].msgid = sc->sc_msgid++; + PLCI = (sc->sc_bchan[cd->channelid].ncci & CAPI_PLCI_MASK); + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, I4BCAPI_APPLID); + msg = capimsg_setu16(msg, CAPI_CONNECT_B3_REQ); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, PLCI); + msg = capimsg_setu8(msg, 0); /* NCPI */ + + sc->send(sc, m); +} + +void capi_connect_b3_conf(capi_softc_t *sc, struct mbuf *m_in) +{ + u_int8_t *msg = mtod(m_in, u_int8_t*); + call_desc_t *cd; + u_int16_t msgid; + u_int32_t NCCI; + u_int16_t Info; + int bch; + + msg = capimsg_getu16(msg + 6, &msgid); + msg = capimsg_getu32(msg, &NCCI); + msg = capimsg_getu16(msg, &Info); + + for (bch = 0; bch < sc->sc_nbch; bch++) + if ((sc->sc_bchan[bch].state == B_CONNECT_B3_CONF) && + (sc->sc_bchan[bch].ncci == (NCCI & CAPI_PLCI_MASK))) + break; + + if ((bch == sc->sc_nbch) || + (cd = cd_by_cdid(sc->sc_bchan[bch].cdid)) == NULL) { + printf("capi%d: can't find channel for connect_b3_conf NCCI %x\n", + sc->sc_unit, NCCI); + return; + } + + if (Info == 0) { + sc->sc_bchan[bch].ncci = NCCI; + sc->sc_bchan[bch].state = B_CONNECT_B3_ACTIVE_IND; + + } else { + struct isdn_l3_driver *l3drv; + + l3drv = isdn_find_l3_by_bri(sc->capi_bri); + + SET_CAUSE_TV(cd->cause_in, CAUSET_I4B, CAUSE_I4B_OOO); /* XXX */ + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); + + l3drv->bch_state[bch] = BCH_ST_RSVD; + + printf("capi%d: can't connect_b3 out, info=%04x\n", sc->sc_unit, Info); + + capi_disconnect_req(sc, cd); + } +} + +void capi_connect_b3_active_ind(capi_softc_t *sc, struct mbuf *m_in) +{ + struct mbuf *m = i4b_Dgetmbuf(8 + 4); + u_int8_t *msg = mtod(m_in, u_int8_t*); + call_desc_t *cd; + u_int16_t applid, msgid; + u_int32_t NCCI; + int bch; + + if (!m) { + printf("capi%d: can't get mbuf for b3_active_ind\n", sc->sc_unit); + return; + } + + msg = capimsg_getu16(msg + 2, &applid); + msg = capimsg_getu16(msg + 2, &msgid); + msg = capimsg_getu32(msg, &NCCI); + + for (bch = 0; bch < sc->sc_nbch; bch++) + if ((sc->sc_bchan[bch].state == B_CONNECT_B3_ACTIVE_IND) && + (sc->sc_bchan[bch].ncci == NCCI)) + break; + + if ((bch == sc->sc_nbch) || + (cd = cd_by_cdid(sc->sc_bchan[bch].cdid)) == NULL) { + printf("capi%d: can't find channel for b3_active_resp NCCI %x\n", + sc->sc_unit, NCCI); + return; + } + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, I4BCAPI_APPLID); + msg = capimsg_setu16(msg, CAPI_CONNECT_B3_ACTIVE_RESP); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, NCCI); + + sc->send(sc, m); + + sc->sc_bchan[bch].state = B_CONNECTED; + + i4b_l4_connect_active_ind(cd); +} + +/* +// Incoming call setup: +// -------------------- +// +// <-- CAPI_CONNECT_IND +// (consult Layer 4) +// CAPI_CONNECT_RESP --> +// <-- CAPI_CONNECT_ACTIVE_IND +// CAPI_CONNECT_ACTIVE_RESP --> +// <-- CAPI_CONNECT_B3_IND +// CAPI_CONNECT_B3_RESP --> +// <-- CAPI_CONNECT_B3_ACTIVE_IND +// CAPI_CONNECT_B3_ACTIVE_RESP --> +// (notify Layer 4) +*/ + +void capi_connect_ind(capi_softc_t *sc, struct mbuf *m_in) +{ + u_int8_t *msg = mtod(m_in, u_int8_t*); + call_desc_t *cd; + u_int16_t applid, msgid; + u_int32_t PLCI; + u_int16_t CIP; + u_int8_t x, y, z; + int bch; + + if ((cd = reserve_cd()) == NULL) { + printf("capi%d: can't get cd for connect_ind\n", sc->sc_unit); + return; + } + + cd->bri = sc->capi_bri; + cd->channelexcl = 0; + + for (bch = 0; bch < sc->sc_nbch; bch++) + if (sc->sc_bchan[bch].state == B_FREE) + break; + + sc->sc_bchan[bch].state = B_CONNECT_IND; + cd->channelid = bch; /* XXX CHAN_ANY XXX */ + + cd->crflag = CRF_DEST; + cd->cr = get_rand_cr(sc->sc_unit); + cd->scr_ind = SCR_NONE; + cd->prs_ind = PRS_NONE; + cd->bprot = BPROT_NONE; + cd->ilt = NULL; + cd->display[0] = '\0'; + cd->datetime[0] = '\0'; + + msg = capimsg_getu16(msg + 2, &applid); + msg = capimsg_getu16(msg + 2, &msgid); + msg = capimsg_getu32(msg, &PLCI); + msg = capimsg_getu16(msg, &CIP); + + cd->event = (int) msgid; /* XXX overload */ + cd->Q931state = (int) PLCI; /* XXX overload */ + + switch (CIP) { + case 0x0010: + case 0x0001: cd->bprot = BPROT_NONE; break; + case 0x0002: cd->bprot = BPROT_RHDLC; break; + default: +#if 0 + NDBGL4(L4_CAPIDBG, "capi%d: unknown CIP = %d", sc->sc_unit, CIP); +#endif + cd->bprot = BPROT_NONE; + } + + msg = capimsg_getu8(msg, &x); /* Called party struct len */ + if (x) { + msg = capimsg_getu8(msg, &y); /* Numbering plan */ + z = x - 1; + if (z >= TELNO_MAX) z = (TELNO_MAX-1); + strncpy(cd->dst_telno, msg, z); + msg += x; + x = z; + } + cd->dst_telno[x] = '\0'; + + msg = capimsg_getu8(msg, &x); /* Calling party struct len */ + if (x) { + msg = capimsg_getu8(msg, &y); /* Numbering plan */ + msg = capimsg_getu8(msg, &y); /* Screening/Presentation */ + if ((y & 0x80) == 0) { /* screening used */ + cd->scr_ind = (y & 3) + SCR_USR_NOSC; + cd->prs_ind = ((y >> 5) & 3) + PRS_ALLOWED; + } + z = x - 2; + if (z >= TELNO_MAX) z = (TELNO_MAX-1); + strncpy(cd->src_telno, msg, z); + msg += x; + x = z; + } + cd->src_telno[x] = '\0'; + + i4b_l4_connect_ind(cd); +} + +void capi_connect_resp(capi_softc_t *sc, call_desc_t *cd) +{ + struct isdn_l3_driver *l3drv; + struct mbuf *m; + u_int8_t *msg; + u_int16_t msgid; + u_int32_t PLCI; + int dlen = strlen(cd->dst_telno); + + m = i4b_Dgetmbuf(8 + 21 + dlen); + if (!m) { + printf("capi%d: can't get mbuf for connect_resp\n", sc->sc_unit); + return; + } + + l3drv = isdn_find_l3_by_bri(sc->capi_bri); + + msgid = (u_int16_t) cd->event; + PLCI = (u_int32_t) cd->Q931state; + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, I4BCAPI_APPLID); + msg = capimsg_setu16(msg, CAPI_CONNECT_RESP); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, PLCI); + + switch (cd->response) { + case SETUP_RESP_ACCEPT: + sc->sc_bchan[cd->channelid].cdid = cd->cdid; + sc->sc_bchan[cd->channelid].ncci = PLCI; + sc->sc_bchan[cd->channelid].state = B_CONNECT_ACTIVE_IND; + l3drv->bch_state[cd->channelid] = BCH_ST_USED; + msg = capimsg_setu16(msg, 0); /* Accept the call */ + break; + + case SETUP_RESP_REJECT: + sc->sc_bchan[cd->channelid].state = B_FREE; + l3drv->bch_state[cd->channelid] = BCH_ST_FREE; + msg = capimsg_setu16(msg, 2); /* Reject, normal call clearing */ + break; + + case SETUP_RESP_DNTCRE: + sc->sc_bchan[cd->channelid].state = B_FREE; + l3drv->bch_state[cd->channelid] = BCH_ST_FREE; + if (sc->sc_nbch == 30) { + /* With PRI, we can't really ignore calls -- normal clearing */ + msg = capimsg_setu16(msg, (0x3480|CAUSE_Q850_NCCLR)); + } else { + msg = capimsg_setu16(msg, 1); /* Ignore */ + } + break; + + default: + sc->sc_bchan[cd->channelid].state = B_FREE; + l3drv->bch_state[cd->channelid] = BCH_ST_FREE; + msg = capimsg_setu16(msg, (0x3480|CAUSE_Q850_CALLREJ)); + } + + msg = capimsg_setu8(msg, 15); /* B protocol */ + if (cd->bprot == BPROT_NONE) + msg = capimsg_setu16(msg, 1); /* B1 protocol = transparent */ + else + msg = capimsg_setu16(msg, 0); /* B1 protocol = HDLC */ + msg = capimsg_setu16(msg, 1); /* B2 protocol = transparent */ + msg = capimsg_setu16(msg, 0); /* B3 protocol = transparent */ + msg = capimsg_setu8(msg, 0); /* B1 parameters */ + msg = capimsg_setu8(msg, 0); /* B2 parameters */ + msg = capimsg_setu8(msg, 0); /* B3 parameters */ + + msg = capimsg_setu8(msg, 1 + dlen); + msg = capimsg_setu8(msg, 0x80); /* Numbering plan */ + strncpy(msg, cd->dst_telno, dlen); + msg = capimsg_setu8(msg + dlen, 0); /* Connected subaddress */ + msg = capimsg_setu8(msg, 0); /* Low Layer Compatibility */ + msg = capimsg_setu8(msg, 0); /* Additional Info */ + + sc->send(sc, m); +} + +void capi_connect_b3_ind(capi_softc_t *sc, struct mbuf *m_in) +{ + struct mbuf *m = i4b_Dgetmbuf(8 + 7); + u_int8_t *msg = mtod(m_in, u_int8_t*); + u_int16_t applid, msgid; + u_int32_t NCCI; + int bch; + + if (!m) { + printf("capi%d: can't get mbuf for connect_b3_resp\n", sc->sc_unit); + return; + } + + msg = capimsg_getu16(msg + 2, &applid); + msg = capimsg_getu16(msg + 2, &msgid); + msg = capimsg_getu32(msg, &NCCI); + + for (bch = 0; bch < sc->sc_nbch; bch++) + if ((sc->sc_bchan[bch].state == B_CONNECT_B3_IND) && + (sc->sc_bchan[bch].ncci == (NCCI & CAPI_PLCI_MASK))) + break; + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, applid); + msg = capimsg_setu16(msg, CAPI_CONNECT_B3_RESP); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, NCCI); + + if (bch == sc->sc_nbch) { + printf("capi%d: can't get cd for connect_b3_resp NCCI %x\n", + sc->sc_unit, NCCI); + msg = capimsg_setu16(msg, 8); /* Reject, destination OOO */ + + } else { + sc->sc_bchan[bch].ncci = NCCI; + sc->sc_bchan[bch].state = B_CONNECT_B3_ACTIVE_IND; + msg = capimsg_setu16(msg, 0); /* Accept */ + } + + msg = capimsg_setu8(msg, 0); /* NCPI */ + + sc->send(sc, m); +} + +/* +// Data transfer: +// -------------- +*/ + +void capi_data_b3_req(capi_softc_t *sc, int chan, struct mbuf *m_b3) +{ + struct mbuf *m = i4b_Dgetmbuf(8 + 14); + u_int8_t *msg; + u_int16_t msgid; + + if (!m) { + printf("capi%d: can't get mbuf for data_b3_req\n", sc->sc_unit); + return; + } + + msgid = sc->sc_bchan[chan].msgid = sc->sc_msgid++; + sc->sc_bchan[chan].busy = 1; + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, I4BCAPI_APPLID); + msg = capimsg_setu16(msg, CAPI_DATA_B3_REQ); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, sc->sc_bchan[chan].ncci); + msg = capimsg_setu32(msg, (u_int32_t) m_b3->m_data); /* Pointer */ + msg = capimsg_setu16(msg, m_b3->m_len); + msg = capimsg_setu16(msg, chan); + msg = capimsg_setu16(msg, 0); /* Flags */ + + m->m_next = m_b3; + + sc->send(sc, m); +} + +void capi_data_b3_conf(capi_softc_t *sc, struct mbuf *m_in) +{ + u_int8_t *msg = mtod(m_in, u_int8_t*); + u_int32_t NCCI; + u_int16_t handle; + u_int16_t Info; + + msg = capimsg_getu32(msg + 8, &NCCI); + msg = capimsg_getu16(msg, &handle); + msg = capimsg_getu16(msg, &Info); + + if (Info == 0) { + sc->sc_bchan[handle].busy = 0; + capi_start_tx(sc, handle); + + } else { + printf("capi%d: data_b3_conf NCCI %x handle %x info=%04x\n", + sc->sc_unit, NCCI, handle, Info); + } +} + +void capi_data_b3_ind(capi_softc_t *sc, struct mbuf *m_in) +{ + struct mbuf *m = i4b_Dgetmbuf(8 + 6); + u_int8_t *msg = mtod(m_in, u_int8_t*); + u_int16_t applid, msgid; + u_int32_t NCCI; + u_int16_t handle; + int bch; + + if (!m) { + printf("capi%d: can't get mbuf for data_b3_resp\n", sc->sc_unit); + return; + } + + msg = capimsg_getu16(msg + 2, &applid); + msg = capimsg_getu16(msg + 2, &msgid); + msg = capimsg_getu32(msg, &NCCI); + msg = capimsg_getu16(msg + 6, &handle); + + for (bch = 0; bch < sc->sc_nbch; bch++) + if ((sc->sc_bchan[bch].state == B_CONNECTED) && + (sc->sc_bchan[bch].ncci == NCCI)) + break; + + if (bch == sc->sc_nbch) { + printf("capi%d: can't find channel for data_b3_ind NCCI %x\n", + sc->sc_unit, NCCI); + + } else { + if (sc->sc_bchan[bch].bprot == BPROT_RHDLC) { + /* HDLC drivers use rx_mbuf */ + + sc->sc_bchan[bch].in_mbuf = m_in->m_next; + sc->sc_bchan[bch].rxcount += m_in->m_next->m_len; + m_in->m_next = NULL; /* driver frees */ + + (*sc->sc_bchan[bch].l4_driver->bch_rx_data_ready)( + sc->sc_bchan[bch].l4_driver_softc); + + } else { + /* Telephony drivers use rx_queue */ + + if (!IF_QFULL(&sc->sc_bchan[bch].rx_queue)) { + IF_ENQUEUE(&sc->sc_bchan[bch].rx_queue, m_in->m_next); + sc->sc_bchan[bch].rxcount += m_in->m_next->m_len; + m_in->m_next = NULL; /* driver frees */ + } + + (*sc->sc_bchan[bch].l4_driver->bch_rx_data_ready)( + sc->sc_bchan[bch].l4_driver_softc); + } + } + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, I4BCAPI_APPLID); + msg = capimsg_setu16(msg, CAPI_DATA_B3_RESP); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, NCCI); + msg = capimsg_setu16(msg, handle); + + sc->send(sc, m); +} + +/* +// Connection teardown: +// -------------------- +*/ + +void capi_disconnect_req(capi_softc_t *sc, call_desc_t *cd) +{ + struct isdn_l3_driver *l3drv; + struct mbuf *m = i4b_Dgetmbuf(8 + 5); + u_int8_t *msg; + u_int16_t msgid; + u_int32_t PLCI; + + if (!m) { + printf("capi%d: can't get mbuf for disconnect_req\n", sc->sc_unit); + return; + } + + l3drv = isdn_find_l3_by_bri(sc->capi_bri); + + sc->sc_bchan[cd->channelid].state = B_DISCONNECT_CONF; + l3drv->bch_state[cd->channelid] = BCH_ST_RSVD; + msgid = sc->sc_bchan[cd->channelid].msgid = sc->sc_msgid++; + PLCI = (sc->sc_bchan[cd->channelid].ncci & CAPI_PLCI_MASK); + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, I4BCAPI_APPLID); + msg = capimsg_setu16(msg, CAPI_DISCONNECT_REQ); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, PLCI); + msg = capimsg_setu8(msg, 0); /* Additional Info */ + + sc->send(sc, m); +} + +void capi_disconnect_conf(capi_softc_t *sc, struct mbuf *m_in) +{ + struct isdn_l3_driver *l3drv; + u_int8_t *msg = mtod(m_in, u_int8_t*); + call_desc_t *cd; + u_int32_t PLCI; + int bch; + + msg = capimsg_getu32(msg + 8, &PLCI); + + for (bch = 0; bch < sc->sc_nbch; bch++) + if ((sc->sc_bchan[bch].state == B_DISCONNECT_CONF) && + ((sc->sc_bchan[bch].ncci & CAPI_PLCI_MASK) == PLCI)) + break; + + if (bch == sc->sc_nbch) { + printf("capi%d: can't find channel for disconnect_conf PLCI %x\n", + sc->sc_unit, PLCI); + return; + } + + cd = cd_by_cdid(sc->sc_bchan[bch].cdid); + if (!cd) { + printf("capi%d: can't find cd for disconnect_conf PLCI %x\n", + sc->sc_unit, PLCI); + } else { + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); + } + + l3drv = isdn_find_l3_by_bri(sc->capi_bri); + + sc->sc_bchan[bch].state = B_FREE; + l3drv->bch_state[bch] = BCH_ST_FREE; +} + +void capi_disconnect_b3_ind(capi_softc_t *sc, struct mbuf *m_in) +{ + struct mbuf *m = i4b_Dgetmbuf(8 + 4); + u_int8_t *msg = mtod(m_in, u_int8_t*); + u_int16_t applid, msgid; + u_int32_t NCCI; + + if (!m) { + printf("capi%d: can't get mbuf for disconnect_b3_resp\n", sc->sc_unit); + return; + } + + msg = capimsg_getu16(msg + 2, &applid); + msg = capimsg_getu16(msg + 2, &msgid); + msg = capimsg_getu32(msg, &NCCI); + + /* XXX update bchan state? XXX */ + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, applid); + msg = capimsg_setu16(msg, CAPI_DISCONNECT_B3_RESP); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, NCCI); + + sc->send(sc, m); +} + +void capi_disconnect_ind(capi_softc_t *sc, struct mbuf *m_in) +{ + struct isdn_l3_driver *l3drv; + struct mbuf *m = i4b_Dgetmbuf(8 + 4); + u_int8_t *msg = mtod(m_in, u_int8_t*); + call_desc_t *cd; + u_int16_t applid, msgid; + u_int32_t PLCI; + u_int16_t Reason; + int bch; + + if (!m) { + printf("capi%d: can't get mbuf for disconnect_resp\n", sc->sc_unit); + return; + } + + msg = capimsg_getu16(msg + 2, &applid); + msg = capimsg_getu16(msg + 2, &msgid); + msg = capimsg_getu32(msg, &PLCI); + msg = capimsg_getu16(msg, &Reason); + + for (bch = 0; bch < sc->sc_nbch; bch++) + if ((sc->sc_bchan[bch].state != B_FREE) && + ((sc->sc_bchan[bch].ncci & CAPI_PLCI_MASK) == PLCI)) + break; + + if (bch < sc->sc_nbch) { + /* We may not have a bchan assigned if call was ignored. */ + + cd = cd_by_cdid(sc->sc_bchan[bch].cdid); + sc->sc_bchan[bch].state = B_DISCONNECT_IND; + } else + cd = NULL; + + if (cd) { + if ((Reason & 0xff00) == 0x3400) { + SET_CAUSE_TV(cd->cause_in, CAUSET_Q850, (Reason & 0x7f)); + } else { + SET_CAUSE_TV(cd->cause_in, CAUSET_I4B, CAUSE_I4B_NORMAL); + } + + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); + + sc->sc_bchan[bch].state = B_FREE; + l3drv = isdn_find_l3_by_bri(sc->capi_bri); + l3drv->bch_state[bch] = BCH_ST_FREE; + } + + msg = capimsg_setu16(mtod(m, u_int8_t*), m->m_len); + msg = capimsg_setu16(msg, applid); + msg = capimsg_setu16(msg, CAPI_DISCONNECT_RESP); + msg = capimsg_setu16(msg, msgid); + + msg = capimsg_setu32(msg, PLCI); + + sc->send(sc, m); +} diff --git a/sys/netisdn/i4b_capi_msgs.h b/sys/netisdn/i4b_capi_msgs.h new file mode 100644 index 000000000000..44e40145ba99 --- /dev/null +++ b/sys/netisdn/i4b_capi_msgs.h @@ -0,0 +1,382 @@ +/* $NetBSD: i4b_capi_msgs.h,v 1.1 2003/09/25 15:34:38 pooka Exp $ */ + +/* + * Copyright (c) 2001-2003 Cubical Solutions Ltd. 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. + * + * capi/capi_msgs.h The CAPI i4b message and handler declarations. + * + * $FreeBSD: src/sys/i4b/capi/capi_msgs.h,v 1.1 2001/05/25 08:39:31 hm Exp $ + */ + +#ifndef _I4B_CAPI_MSGS_H_ +#define _I4B_CAPI_MSGS_H_ + +/* CAPI commands */ + +#define CAPI_ALERT 0x01 +#define CAPI_CONNECT 0x02 +#define CAPI_CONNECT_ACTIVE 0x03 +#define CAPI_CONNECT_B3 0x82 +#define CAPI_CONNECT_B3_ACTIVE 0x83 +#define CAPI_CONNECT_B3_T90_ACTIVE 0x88 +#define CAPI_DATA_B3 0x86 +#define CAPI_DISCONNECT_B3 0x84 +#define CAPI_DISCONNECT 0x04 +#define CAPI_FACILITY 0x80 +#define CAPI_INFO 0x08 +#define CAPI_LISTEN 0x05 +#define CAPI_MANUFACTURER 0xff +#define CAPI_RESET_B3 0x87 +#define CAPI_SELECT_B_PROTOCOL 0x41 + +/* CAPI subcommands */ + +#define CAPI_REQ 0x80 +#define CAPI_CONF 0x81 +#define CAPI_IND 0x82 +#define CAPI_RESP 0x83 + +/* CAPI combined commands */ + +#define CAPICMD(cmd,subcmd) (((subcmd)<<8)|(cmd)) + +#define CAPI_DISCONNECT_REQ CAPICMD(CAPI_DISCONNECT,CAPI_REQ) +#define CAPI_DISCONNECT_CONF CAPICMD(CAPI_DISCONNECT,CAPI_CONF) +#define CAPI_DISCONNECT_IND CAPICMD(CAPI_DISCONNECT,CAPI_IND) +#define CAPI_DISCONNECT_RESP CAPICMD(CAPI_DISCONNECT,CAPI_RESP) + +#define CAPI_ALERT_REQ CAPICMD(CAPI_ALERT,CAPI_REQ) +#define CAPI_ALERT_CONF CAPICMD(CAPI_ALERT,CAPI_CONF) + +#define CAPI_CONNECT_REQ CAPICMD(CAPI_CONNECT,CAPI_REQ) +#define CAPI_CONNECT_CONF CAPICMD(CAPI_CONNECT,CAPI_CONF) +#define CAPI_CONNECT_IND CAPICMD(CAPI_CONNECT,CAPI_IND) +#define CAPI_CONNECT_RESP CAPICMD(CAPI_CONNECT,CAPI_RESP) + +#define CAPI_CONNECT_ACTIVE_REQ CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_REQ) +#define CAPI_CONNECT_ACTIVE_CONF CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_CONF) +#define CAPI_CONNECT_ACTIVE_IND CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_IND) +#define CAPI_CONNECT_ACTIVE_RESP CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_RESP) + +#define CAPI_SELECT_B_PROTOCOL_REQ CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_REQ) +#define CAPI_SELECT_B_PROTOCOL_CONF CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_CONF) + +#define CAPI_CONNECT_B3_REQ CAPICMD(CAPI_CONNECT_B3,CAPI_REQ) +#define CAPI_CONNECT_B3_CONF CAPICMD(CAPI_CONNECT_B3,CAPI_CONF) +#define CAPI_CONNECT_B3_IND CAPICMD(CAPI_CONNECT_B3,CAPI_IND) +#define CAPI_CONNECT_B3_RESP CAPICMD(CAPI_CONNECT_B3,CAPI_RESP) + +#define CAPI_CONNECT_B3_ACTIVE_REQ CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_REQ) +#define CAPI_CONNECT_B3_ACTIVE_CONF CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_CONF) +#define CAPI_CONNECT_B3_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_IND) +#define CAPI_CONNECT_B3_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_RESP) + +#define CAPI_CONNECT_B3_T90_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_IND) +#define CAPI_CONNECT_B3_T90_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_RESP) + +#define CAPI_DATA_B3_REQ CAPICMD(CAPI_DATA_B3,CAPI_REQ) +#define CAPI_DATA_B3_CONF CAPICMD(CAPI_DATA_B3,CAPI_CONF) +#define CAPI_DATA_B3_IND CAPICMD(CAPI_DATA_B3,CAPI_IND) +#define CAPI_DATA_B3_RESP CAPICMD(CAPI_DATA_B3,CAPI_RESP) + +#define CAPI_DISCONNECT_B3_REQ CAPICMD(CAPI_DISCONNECT_B3,CAPI_REQ) +#define CAPI_DISCONNECT_B3_CONF CAPICMD(CAPI_DISCONNECT_B3,CAPI_CONF) +#define CAPI_DISCONNECT_B3_IND CAPICMD(CAPI_DISCONNECT_B3,CAPI_IND) +#define CAPI_DISCONNECT_B3_RESP CAPICMD(CAPI_DISCONNECT_B3,CAPI_RESP) + +#define CAPI_RESET_B3_REQ CAPICMD(CAPI_RESET_B3,CAPI_REQ) +#define CAPI_RESET_B3_CONF CAPICMD(CAPI_RESET_B3,CAPI_CONF) +#define CAPI_RESET_B3_IND CAPICMD(CAPI_RESET_B3,CAPI_IND) +#define CAPI_RESET_B3_RESP CAPICMD(CAPI_RESET_B3,CAPI_RESP) + +#define CAPI_LISTEN_REQ CAPICMD(CAPI_LISTEN,CAPI_REQ) +#define CAPI_LISTEN_CONF CAPICMD(CAPI_LISTEN,CAPI_CONF) + +#define CAPI_MANUFACTURER_REQ CAPICMD(CAPI_MANUFACTURER,CAPI_REQ) +#define CAPI_MANUFACTURER_CONF CAPICMD(CAPI_MANUFACTURER,CAPI_CONF) +#define CAPI_MANUFACTURER_IND CAPICMD(CAPI_MANUFACTURER,CAPI_IND) +#define CAPI_MANUFACTURER_RESP CAPICMD(CAPI_MANUFACTURER,CAPI_RESP) + +#define CAPI_FACILITY_REQ CAPICMD(CAPI_FACILITY,CAPI_REQ) +#define CAPI_FACILITY_CONF CAPICMD(CAPI_FACILITY,CAPI_CONF) +#define CAPI_FACILITY_IND CAPICMD(CAPI_FACILITY,CAPI_IND) +#define CAPI_FACILITY_RESP CAPICMD(CAPI_FACILITY,CAPI_RESP) + +#define CAPI_INFO_REQ CAPICMD(CAPI_INFO,CAPI_REQ) +#define CAPI_INFO_CONF CAPICMD(CAPI_INFO,CAPI_CONF) +#define CAPI_INFO_IND CAPICMD(CAPI_INFO,CAPI_IND) +#define CAPI_INFO_RESP CAPICMD(CAPI_INFO,CAPI_RESP) + +/* CAPI message access helpers */ + +/* + * CAPI message header: + * word Length + * word ApplId + * byte Command + * byte Subcommand + * word MsgId + * + * Note that in the following, Controller/PLCI/NCCI is coded as follows: + * bits 0..6 = controller, bit 7 = ext/int, bits 8..15 = PLCI, and + * bits 16..31 = NCCI value. + * + * ALERT_REQ, 01 80: + * dword PLCI + * struct Additional Info + * + * ALERT_CONF, 01 81: + * dword PLCI + * word Info (0 = OK, other = cause) + * + * CONNECT_REQ, 02 80: + * dword controller + * word CIP + * struct Called party number + * struct Calling party number + * struct Called party subaddress + * struct Calling party subaddress + * struct Bearer Capability + * struct Low Layer Compatibility + * struct High Layer Compatibility + * struct Additional Info + * + * CONNECT_CONF, 02 81: + * dword PLCI + * word Info (0 = OK, other = cause) + * + * CONNECT_IND, 02 82: + * dword PLCI + * word CIP + * struct Called party number + * struct Calling party number + * struct Called party subaddress + * struct Calling party subaddress + * struct Bearer Capability + * struct Low Layer Compatibility + * struct High Layer Compatibility + * struct Additional Info + * struct Second Calling party number + * + * CONNECT_RESP, 02 83: + * dword PLCI + * word Reject (0 = accept, 1 = ignore, 2 = reject/normal clearing) + * struct B protocol + * struct Connected number + * struct Connected subaddress + * struct Low Layer Compatibility + * struct Additional Info + * + * CONNECT_ACTIVE_IND, 03 82: + * dword PLCI + * struct Connected number + * struct Connected subaddress + * struct Low Layer Compatibility + * + * CONNECT_ACTIVE_RESP, 03 83: + * dword PLCI + * + * CONNECT_B3_REQ, 82 80: + * dword PLCI + * struct NCPI + * + * CONNECT_B3_CONF, 82 81: + * dword NCCI + * word Info (0 = connected, other = cause) + * + * CONNECT_B3_IND, 82 82: + * dword NCCI + * struct NCPI + * + * CONNECT_B3_RESP, 82 83: + * dword NCCI + * word Reject (0 = accept, 2 = reject/normal clearing) + * struct NCPI + * + * CONNECT_B3_ACTIVE_IND, 83 82: + * dword NCCI + * struct NCPI + * + * CONNECT_B3_ACTIVE_RESP, 83 83: + * dword NCCI + * + * DATA_B3_REQ, 86 80: + * dword NCCI + * dword Data pointer + * word Data length + * word Data handle (packet id) + * word Flags (02 = more) + * + * DATA_B3_CONF, 86 81: + * dword NCCI + * word Data handle (packet id) + * word Info (0 = OK, other = cause) + * + * DATA_B3_IND, 86 82: + * dword NCCI + * dword Data pointer + * word Data length + * word Data handle (packet id) + * word Flags (02 = more) + * + * DATA_B3_RESP, 86 83: + * dword NCCI + * word Data handle (packet id) + * + * DISCONNECT_B3_REQ, 84 80: + * dword NCCI + * struct NCPI + * + * DISCONNECT_B3_CONF, 84 81: + * dword NCCI + * word Info (0 = OK, other = cause) + * + * DISCONNECT_B3_IND, 84 82: + * dword NCCI + * word Reason + * struct NCPI + * + * DISCONNECT_B3_RESP, 84 83: + * dword NCCI + * + * DISCONNECT_REQ, 04 80: + * dword PLCI + * struct Additional Info + * + * DISCONNECT_CONF, 04 81: + * dword PLCI + * word Info (0 = OK, other = cause) + * + * DISCONNECT_IND, 04 82: + * dword PLCI + * word Reason + * + * DISCONNECT_RESP, 04 83: + * dword PLCI + * + * LISTEN_REQ, 05 80: + * dword Controller + * dword Info mask (bits 0..9 used) + * dword CIP Mask (bit 0 = any match) + * dword CIP Mask 2 (bit 0 = any match) + * struct Calling party number + * struct Calling party subaddress + * + * LISTEN_CONF, 05 81: + * dword Controller + * word Info (0 = OK, other = cause) + * + * INFO_REQ, 08 80: + * dword Controller/PLCI + * struct Called party number + * struct Additional Info + * + * INFO_CONF, 08 81: + * dword Controller/PLCI + * word Info (0 = OK, other = cause) + * + * INFO_IND, 08 82: + * dword Controller/PLCI + * word Info number + * struct Info element + * + * INFO_RESP, 08 83: + * dword Controller/PLCI + */ + +#define CAPIMSG_LEN(msg) (msg[0]|(msg[1]<<8)) +#define CAPIMSG_DATALEN(msg) (msg[16]|(msg[17]<<8)) + +static __inline u_int8_t* capimsg_getu8(u_int8_t *msg, u_int8_t *val) +{ + *val = *msg; + return (msg + 1); +} + +static __inline u_int8_t* capimsg_getu16(u_int8_t *msg, u_int16_t *val) +{ + *val = (msg[0]|(msg[1]<<8)); + return (msg + 2); +} + +static __inline u_int8_t* capimsg_getu32(u_int8_t *msg, u_int32_t *val) +{ + *val = (msg[0]|(msg[1]<<8)|(msg[2]<<16)|(msg[3]<<24)); + return (msg + 4); +} + +static __inline u_int8_t* capimsg_setu8(u_int8_t *msg, u_int8_t val) +{ + msg[0] = val; + return (msg + 1); +} + +static __inline u_int8_t* capimsg_setu16(u_int8_t *msg, u_int16_t val) +{ + msg[0] = (val & 0xff); + msg[1] = (val >> 8) & 0xff; + return (msg + 2); +} + +static __inline u_int8_t* capimsg_setu32(u_int8_t *msg, u_int32_t val) +{ + msg[0] = (val & 0xff); + msg[1] = (val >> 8) & 0xff; + msg[2] = (val >> 16) & 0xff; + msg[3] = (val >> 24) & 0xff; + return (msg + 4); +} + +/* +// CAPI message handlers called by higher layers +*/ + +extern void capi_listen_req(capi_softc_t *sc, u_int32_t CIP); +extern void capi_alert_req(capi_softc_t *sc, call_desc_t *cd); +extern void capi_connect_req(capi_softc_t *sc, call_desc_t *cd); +extern void capi_connect_b3_req(capi_softc_t *sc, call_desc_t *cd); +extern void capi_connect_resp(capi_softc_t *sc, call_desc_t *cd); +extern void capi_data_b3_req(capi_softc_t *sc, int chan, struct mbuf *m); +extern void capi_disconnect_req(capi_softc_t *sc, call_desc_t *cd); + +/* +// CAPI message handlers called by the receive routine +*/ + +extern void capi_listen_conf(capi_softc_t *sc, struct mbuf *m); +extern void capi_info_ind(capi_softc_t *sc, struct mbuf *m); +extern void capi_alert_conf(capi_softc_t *sc, struct mbuf *m); +extern void capi_connect_conf(capi_softc_t *sc, struct mbuf *m); +extern void capi_connect_active_ind(capi_softc_t *sc, struct mbuf *m); +extern void capi_connect_b3_conf(capi_softc_t *sc, struct mbuf *m); +extern void capi_connect_b3_active_ind(capi_softc_t *sc, struct mbuf *m); +extern void capi_connect_ind(capi_softc_t *sc, struct mbuf *m); +extern void capi_connect_b3_ind(capi_softc_t *sc, struct mbuf *m); +extern void capi_data_b3_conf(capi_softc_t *sc, struct mbuf *m); +extern void capi_data_b3_ind(capi_softc_t *sc, struct mbuf *m); +extern void capi_disconnect_conf(capi_softc_t *sc, struct mbuf *m); +extern void capi_disconnect_b3_ind(capi_softc_t *sc, struct mbuf *m); +extern void capi_disconnect_ind(capi_softc_t *sc, struct mbuf *m); + +#endif /* _I4B_CAPI_MSGS_H_ */