983 lines
27 KiB
C
983 lines
27 KiB
C
/* $NetBSD: i4b_capi_msgs.c,v 1.8 2014/03/20 20:43:35 christos 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 <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: i4b_capi_msgs.c,v 1.8 2014/03/20 20:43:35 christos Exp $");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/mbuf.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/callout.h>
|
|
#include <net/if.h>
|
|
|
|
#include <netisdn/i4b_debug.h>
|
|
#include <netisdn/i4b_ioctl.h>
|
|
#include <netisdn/i4b_cause.h>
|
|
#include <netisdn/i4b_l3l4.h>
|
|
#include <netisdn/i4b_mbuf.h>
|
|
#include <netisdn/i4b_global.h>
|
|
#include <netisdn/i4b_l4.h>
|
|
#include <netisdn/i4b_capi.h>
|
|
#include <netisdn/i4b_capi_msgs.h>
|
|
|
|
/*
|
|
// 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, sc->sc_unit + 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_isdnif(sc->capi_isdnif);
|
|
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_isdnif(sc->capi_isdnif);
|
|
|
|
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, sc->sc_unit + 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_isdnif(sc->capi_isdnif);
|
|
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_isdnif(sc->capi_isdnif);
|
|
|
|
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->isdnif = sc->capi_isdnif;
|
|
cd->channelexcl = 0;
|
|
cd->l3drv = isdn_find_l3_by_isdnif(sc->capi_isdnif);
|
|
|
|
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_isdnif(sc->capi_isdnif);
|
|
|
|
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);
|
|
/* XXX: 32bit Pointer */
|
|
msg = capimsg_setu32(msg, (u_int32_t)(intptr_t)m_b3->m_data);
|
|
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_isdnif(sc->capi_isdnif);
|
|
|
|
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_isdnif(sc->capi_isdnif);
|
|
|
|
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_isdnif(sc->capi_isdnif);
|
|
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);
|
|
}
|