608 lines
17 KiB
C
608 lines
17 KiB
C
/*
|
|
* Copyright (c) 1997, 2000 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_l2if.c - Layer 3 interface to Layer 2
|
|
* -------------------------------------------
|
|
*
|
|
* $Id: i4b_l2if.c,v 1.9 2004/05/06 21:11:04 martin Exp $
|
|
*
|
|
* $FreeBSD$
|
|
*
|
|
* last edit-date: [Fri Jan 5 11:33:47 2001]
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: i4b_l2if.c,v 1.9 2004/05/06 21:11:04 martin Exp $");
|
|
|
|
#ifdef __FreeBSD__
|
|
#include "i4bq931.h"
|
|
#else
|
|
#define NI4BQ931 1
|
|
#endif
|
|
#if NI4BQ931 > 0
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/mbuf.h>
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
|
|
#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
|
|
#include <sys/callout.h>
|
|
#endif
|
|
|
|
#ifdef __FreeBSD__
|
|
#include <machine/i4b_debug.h>
|
|
#include <machine/i4b_ioctl.h>
|
|
#include <machine/i4b_cause.h>
|
|
#else
|
|
#include <netisdn/i4b_debug.h>
|
|
#include <netisdn/i4b_ioctl.h>
|
|
#include <netisdn/i4b_cause.h>
|
|
#endif
|
|
|
|
#include <netisdn/i4b_isdnq931.h>
|
|
#include <netisdn/i4b_l3l4.h>
|
|
#include <netisdn/i4b_mbuf.h>
|
|
|
|
#include <netisdn/i4b_l2.h>
|
|
#include <netisdn/i4b_l1l2.h>
|
|
#include <netisdn/i4b_l3.h>
|
|
#include <netisdn/i4b_l3fsm.h>
|
|
#include <netisdn/i4b_q931.h>
|
|
|
|
#include <netisdn/i4b_l4.h>
|
|
|
|
static unsigned char make_q931_cause(cause_t cause);
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* this converts our internal state (number) to the number specified
|
|
* in Q.931 and is used for reporting our state in STATUS messages.
|
|
*---------------------------------------------------------------------------*/
|
|
int i4b_status_tab[] = {
|
|
0, /* ST_U0, */
|
|
1, /* ST_U1, */
|
|
3, /* ST_U3, */
|
|
4, /* ST_U4, */
|
|
6, /* ST_U6, */
|
|
7, /* ST_U7, */
|
|
8, /* ST_U8, */
|
|
9, /* ST_U9, */
|
|
10, /* ST_U10, */
|
|
11, /* ST_U11, */
|
|
12, /* ST_U12, */
|
|
19, /* ST_U19, */
|
|
6, /* ST_IWA, */
|
|
6, /* ST_IWR, */
|
|
1, /* ST_OW, */
|
|
6, /* ST_IWL, */
|
|
};
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* return a valid q.931/q.850 cause from any of the internal causes
|
|
*---------------------------------------------------------------------------*/
|
|
static unsigned char
|
|
make_q931_cause(cause_t cause)
|
|
{
|
|
register unsigned char ret;
|
|
|
|
switch(GET_CAUSE_TYPE(cause))
|
|
{
|
|
case CAUSET_Q850:
|
|
ret = GET_CAUSE_VAL(cause);
|
|
break;
|
|
case CAUSET_I4B:
|
|
ret = cause_tab_q931[GET_CAUSE_VAL(cause)];
|
|
break;
|
|
default:
|
|
panic("make_q931_cause: unknown cause type!");
|
|
break;
|
|
}
|
|
ret |= EXT_LAST;
|
|
return(ret);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* return status of data link
|
|
*---------------------------------------------------------------------------*/
|
|
int
|
|
i4b_get_dl_stat(call_desc_t *cd)
|
|
{
|
|
const struct isdn_l3_driver * drv = cd->l3drv;
|
|
return drv->dl_est;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* DL ESTABLISH INDICATION from Layer 2
|
|
*---------------------------------------------------------------------------*/
|
|
int
|
|
i4b_dl_establish_ind(struct isdn_l3_driver * drv)
|
|
{
|
|
int i, found;
|
|
NDBGL2(L2_PRIM, "DL-ESTABLISH-IND isdnif %d", drv->isdnif);
|
|
|
|
/* first set DL up in controller descriptor */
|
|
NDBGL3(L3_MSG, "isdnif %d DL established!", drv->isdnif);
|
|
drv->dl_est = DL_UP;
|
|
|
|
found = 0;
|
|
|
|
/* second, inform all (!) active call of the event */
|
|
|
|
for(i=0; i < num_call_desc; i++)
|
|
{
|
|
if( (call_desc[i].cdid != 0)
|
|
&& call_desc[i].isdnif == drv->isdnif) {
|
|
next_l3state(&call_desc[i], EV_DLESTIN);
|
|
found++;
|
|
}
|
|
}
|
|
|
|
if(found == 0)
|
|
{
|
|
NDBGL3(L3_ERR, "ERROR, no cdid for isdnif %d found!",
|
|
drv->isdnif);
|
|
return(-1);
|
|
}
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* DL ESTABLISH CONFIRM from Layer 2
|
|
*---------------------------------------------------------------------------*/
|
|
int
|
|
i4b_dl_establish_cnf(struct isdn_l3_driver * drv)
|
|
{
|
|
int i;
|
|
int found = 0;
|
|
|
|
NDBGL2(L2_PRIM, "DL-ESTABLISH-CONF isdnif %d", drv->isdnif);
|
|
|
|
for(i=0; i < num_call_desc; i++)
|
|
{
|
|
if(call_desc[i].cdid != 0
|
|
&& call_desc[i].isdnif == drv->isdnif) {
|
|
drv->dl_est = DL_UP;
|
|
next_l3state(&call_desc[i], EV_DLESTCF);
|
|
found++;
|
|
}
|
|
}
|
|
|
|
if(found == 0)
|
|
{
|
|
NDBGL3(L3_ERR, "ERROR, no cdid for isdnif %d found!",
|
|
drv->isdnif);
|
|
return(-1);
|
|
}
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* DL RELEASE INDICATION from Layer 2
|
|
*---------------------------------------------------------------------------*/
|
|
int
|
|
i4b_dl_release_ind(struct isdn_l3_driver * drv)
|
|
{
|
|
int i;
|
|
int found = 0;
|
|
|
|
NDBGL2(L2_PRIM, "DL-RELEASE-IND isdnif %d", drv->isdnif);
|
|
|
|
/* first set controller to down */
|
|
|
|
drv->dl_est = DL_DOWN;
|
|
|
|
found = 0;
|
|
|
|
/* second, inform all (!) active calls of the event */
|
|
|
|
for(i=0; i < num_call_desc; i++)
|
|
{
|
|
if(call_desc[i].cdid != 0
|
|
&& call_desc[i].isdnif == drv->isdnif) {
|
|
next_l3state(&call_desc[i], EV_DLRELIN);
|
|
found++;
|
|
}
|
|
}
|
|
|
|
if(found == 0)
|
|
{
|
|
/* this is not an error since it might be a normal call end */
|
|
NDBGL3(L3_MSG, "no cdid for isdnif %d found", drv->isdnif);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* DL RELEASE CONFIRM from Layer 2
|
|
*---------------------------------------------------------------------------*/
|
|
int
|
|
i4b_dl_release_cnf(struct isdn_l3_driver * drv)
|
|
{
|
|
NDBGL2(L2_PRIM, "DL-RELEASE-CONF isdnif %d", drv->isdnif);
|
|
|
|
drv->dl_est = DL_DOWN;
|
|
return(0);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* i4b_dl_data_ind - process a rx'd I-frame got from layer 2
|
|
*---------------------------------------------------------------------------*/
|
|
int
|
|
i4b_dl_data_ind(struct isdn_l3_driver *drv, struct mbuf *m)
|
|
{
|
|
i4b_decode_q931(drv->isdnif, m->m_len, m->m_data);
|
|
i4b_Dfreembuf(m);
|
|
return(0);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* dl_unit_data_ind - process a rx'd U-frame got from layer 2
|
|
*---------------------------------------------------------------------------*/
|
|
int
|
|
i4b_dl_unit_data_ind(struct isdn_l3_driver *drv, struct mbuf *m)
|
|
{
|
|
i4b_decode_q931(drv->isdnif, m->m_len, m->m_data);
|
|
i4b_Dfreembuf(m);
|
|
return(0);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* send CONNECT message
|
|
*---------------------------------------------------------------------------*/
|
|
void
|
|
i4b_l3_tx_connect(call_desc_t *cd)
|
|
{
|
|
struct l2_softc *l2sc = (l2_softc_t*)cd->l3drv->l1_token;
|
|
struct mbuf *m;
|
|
u_char *ptr;
|
|
|
|
NDBGL3(L3_PRIM, "isdnif %d, cr = 0x%02x", cd->isdnif, cd->cr);
|
|
|
|
if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_CONNECT_LEN)) == NULL)
|
|
panic("i4b_l3_tx_connect: can't allocate mbuf");
|
|
|
|
ptr = m->m_data + I_FRAME_HDRLEN;
|
|
|
|
*ptr++ = PD_Q931; /* protocol discriminator */
|
|
*ptr++ = 0x01; /* call reference length */
|
|
*ptr++ = setup_cr(cd, cd->cr); /* call reference value */
|
|
*ptr++ = CONNECT; /* message type = connect */
|
|
|
|
i4b_dl_data_req(l2sc, l2sc->drv, m);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* send RELEASE COMPLETE message
|
|
*---------------------------------------------------------------------------*/
|
|
void
|
|
i4b_l3_tx_release_complete(call_desc_t *cd, int send_cause_flag)
|
|
{
|
|
struct l2_softc *l2sc = (l2_softc_t*)cd->l3drv->l1_token;
|
|
struct mbuf *m;
|
|
u_char *ptr;
|
|
int len = I_FRAME_HDRLEN + MSG_RELEASE_COMPLETE_LEN;
|
|
|
|
if(send_cause_flag == 0)
|
|
{
|
|
len -= 4;
|
|
NDBGL3(L3_PRIM, "isdnif %d, cr = 0x%02x",
|
|
cd->isdnif, cd->cr);
|
|
}
|
|
else
|
|
{
|
|
NDBGL3(L3_PRIM, "isdnif=%d, cr=0x%02x, cause=0x%x",
|
|
cd->isdnif, cd->cr, cd->cause_out);
|
|
}
|
|
|
|
if((m = i4b_Dgetmbuf(len)) == NULL)
|
|
panic("i4b_l3_tx_release_complete: can't allocate mbuf");
|
|
|
|
ptr = m->m_data + I_FRAME_HDRLEN;
|
|
|
|
*ptr++ = PD_Q931; /* protocol discriminator */
|
|
*ptr++ = 0x01; /* call reference length */
|
|
*ptr++ = setup_cr(cd, cd->cr); /* call reference value */
|
|
*ptr++ = RELEASE_COMPLETE; /* message type = release complete */
|
|
|
|
if(send_cause_flag)
|
|
{
|
|
*ptr++ = IEI_CAUSE; /* cause ie */
|
|
*ptr++ = CAUSE_LEN;
|
|
*ptr++ = CAUSE_STD_LOC_OUT;
|
|
*ptr++ = make_q931_cause(cd->cause_out);
|
|
}
|
|
|
|
i4b_dl_data_req(l2sc, l2sc->drv, m);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* send DISCONNECT message
|
|
*---------------------------------------------------------------------------*/
|
|
void
|
|
i4b_l3_tx_disconnect(call_desc_t *cd)
|
|
{
|
|
struct l2_softc *l2sc = (l2_softc_t*)cd->l3drv->l1_token;
|
|
struct mbuf *m;
|
|
u_char *ptr;
|
|
|
|
NDBGL3(L3_PRIM, "isdnif %d, cr = 0x%02x", cd->isdnif, cd->cr);
|
|
|
|
if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_DISCONNECT_LEN)) == NULL)
|
|
panic("i4b_l3_tx_disconnect: can't allocate mbuf");
|
|
|
|
ptr = m->m_data + I_FRAME_HDRLEN;
|
|
|
|
*ptr++ = PD_Q931; /* protocol discriminator */
|
|
*ptr++ = 0x01; /* call ref length */
|
|
*ptr++ = setup_cr(cd, cd->cr); /* call reference value */
|
|
*ptr++ = DISCONNECT; /* message type = disconnect */
|
|
|
|
*ptr++ = IEI_CAUSE; /* cause ie */
|
|
*ptr++ = CAUSE_LEN;
|
|
*ptr++ = CAUSE_STD_LOC_OUT;
|
|
*ptr++ = make_q931_cause(cd->cause_out);
|
|
|
|
i4b_dl_data_req(l2sc, l2sc->drv, m);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* send SETUP message
|
|
*---------------------------------------------------------------------------*/
|
|
void
|
|
i4b_l3_tx_setup(call_desc_t *cd)
|
|
{
|
|
struct l2_softc *l2sc = (l2_softc_t*)cd->l3drv->l1_token;
|
|
struct mbuf *m;
|
|
u_char *ptr;
|
|
int slen = strlen(cd->src_telno);
|
|
int dlen = strlen(cd->dst_telno);
|
|
int msglen = I_FRAME_HDRLEN + MSG_SETUP_LEN + slen + dlen +
|
|
(cd->bprot == BPROT_NONE ? 1 : 0);
|
|
|
|
if (slen == 0)
|
|
msglen -= IEI_CALLINGPN_LEN+2; /* whole IE not send */
|
|
|
|
/*
|
|
* there is one additional octet if cd->bprot == BPROT_NONE
|
|
* NOTE: the selection of a bearer capability by a B L1
|
|
* protocol is highly questionable and a better
|
|
* mechanism should be used in future. (-hm)
|
|
*/
|
|
|
|
NDBGL3(L3_PRIM, "isdnif %d, cr = 0x%02x", cd->isdnif, cd->cr);
|
|
|
|
if((m = i4b_Dgetmbuf(msglen)) == NULL)
|
|
{
|
|
panic("i4b_l3_tx_setup: can't allocate mbuf");
|
|
}
|
|
|
|
cd->crflag = CRF_ORIG; /* we are the originating side */
|
|
|
|
ptr = m->m_data + I_FRAME_HDRLEN;
|
|
|
|
*ptr++ = PD_Q931; /* protocol discriminator */
|
|
*ptr++ = 0x01; /* call ref length */
|
|
*ptr++ = setup_cr(cd, cd->cr); /* call reference value */
|
|
*ptr++ = SETUP; /* message type = setup */
|
|
|
|
*ptr++ = IEI_SENDCOMPL; /* sending complete */
|
|
|
|
*ptr++ = IEI_BEARERCAP; /* bearer capability */
|
|
|
|
/* XXX
|
|
* currently i have no idea if this should be switched by
|
|
* the choosen B channel protocol or if there should be a
|
|
* separate configuration item for the bearer capability.
|
|
* For now, it is switched by the choosen b protocol (-hm)
|
|
*/
|
|
|
|
switch(cd->bprot)
|
|
{
|
|
case BPROT_NONE: /* telephony */
|
|
*ptr++ = IEI_BEARERCAP_LEN+1;
|
|
*ptr++ = IT_CAP_SPEECH;
|
|
*ptr++ = IT_RATE_64K;
|
|
*ptr++ = IT_UL1_G711A;
|
|
break;
|
|
|
|
case BPROT_RHDLC: /* raw HDLC */
|
|
*ptr++ = IEI_BEARERCAP_LEN;
|
|
*ptr++ = IT_CAP_UNR_DIG_INFO;
|
|
*ptr++ = IT_RATE_64K;
|
|
break;
|
|
|
|
default:
|
|
*ptr++ = IEI_BEARERCAP_LEN;
|
|
*ptr++ = IT_CAP_UNR_DIG_INFO;
|
|
*ptr++ = IT_RATE_64K;
|
|
break;
|
|
}
|
|
|
|
*ptr++ = IEI_CHANNELID; /* channel id */
|
|
*ptr++ = IEI_CHANNELID_LEN; /* channel id length */
|
|
|
|
switch(cd->channelid)
|
|
{
|
|
case CHAN_B1:
|
|
*ptr++ = CHANNELID_B1;
|
|
break;
|
|
case CHAN_B2:
|
|
*ptr++ = CHANNELID_B2;
|
|
break;
|
|
default:
|
|
*ptr++ = CHANNELID_ANY;
|
|
break;
|
|
}
|
|
|
|
if (slen) {
|
|
*ptr++ = IEI_CALLINGPN; /* calling party no */
|
|
*ptr++ = IEI_CALLINGPN_LEN+slen;/* calling party no length */
|
|
*ptr++ = NUMBER_TYPEPLAN; /* type of number, number plan id */
|
|
strncpy(ptr, cd->src_telno, slen);
|
|
ptr += slen;
|
|
}
|
|
|
|
*ptr++ = IEI_CALLEDPN; /* called party no */
|
|
*ptr++ = IEI_CALLEDPN_LEN+dlen; /* called party no length */
|
|
*ptr++ = NUMBER_TYPEPLAN; /* type of number, number plan id */
|
|
strncpy(ptr, cd->dst_telno, dlen);
|
|
ptr += dlen;
|
|
|
|
i4b_dl_data_req(l2sc, l2sc->drv, m);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* send CONNECT ACKNOWLEDGE message
|
|
*---------------------------------------------------------------------------*/
|
|
void
|
|
i4b_l3_tx_connect_ack(call_desc_t *cd)
|
|
{
|
|
struct l2_softc *l2sc = (l2_softc_t*)cd->l3drv->l1_token;
|
|
struct mbuf *m;
|
|
u_char *ptr;
|
|
|
|
NDBGL3(L3_PRIM, "isdnif %d, cr = 0x%02x", cd->isdnif, cd->cr);
|
|
|
|
if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_CONNECT_ACK_LEN)) == NULL)
|
|
panic("i4b_l3_tx_connect_ack: can't allocate mbuf");
|
|
|
|
ptr = m->m_data + I_FRAME_HDRLEN;
|
|
|
|
*ptr++ = PD_Q931; /* protocol discriminator */
|
|
*ptr++ = 0x01; /* call reference length */
|
|
*ptr++ = setup_cr(cd, cd->cr); /* call reference value */
|
|
*ptr++ = CONNECT_ACKNOWLEDGE; /* message type = connect ack */
|
|
|
|
i4b_dl_data_req(l2sc, l2sc->drv, m);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* send STATUS message
|
|
*---------------------------------------------------------------------------*/
|
|
void
|
|
i4b_l3_tx_status(call_desc_t *cd, u_char q850cause)
|
|
{
|
|
struct l2_softc *l2sc = (l2_softc_t*)cd->l3drv->l1_token;
|
|
struct mbuf *m;
|
|
u_char *ptr;
|
|
|
|
NDBGL3(L3_PRIM, "isdnif %d, cr = 0x%02x", cd->isdnif, cd->cr);
|
|
|
|
if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_STATUS_LEN)) == NULL)
|
|
panic("i4b_l3_tx_status: can't allocate mbuf");
|
|
|
|
ptr = m->m_data + I_FRAME_HDRLEN;
|
|
|
|
*ptr++ = PD_Q931; /* protocol discriminator */
|
|
*ptr++ = 0x01; /* call reference length */
|
|
*ptr++ = setup_cr(cd, cd->cr); /* call reference value */
|
|
*ptr++ = STATUS; /* message type = connect ack */
|
|
|
|
*ptr++ = IEI_CAUSE; /* cause ie */
|
|
*ptr++ = CAUSE_LEN;
|
|
*ptr++ = CAUSE_STD_LOC_OUT;
|
|
*ptr++ = q850cause | EXT_LAST;
|
|
|
|
*ptr++ = IEI_CALLSTATE; /* call state ie */
|
|
*ptr++ = CALLSTATE_LEN;
|
|
*ptr++ = i4b_status_tab[cd->Q931state];
|
|
|
|
i4b_dl_data_req(l2sc, l2sc->drv, m);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* send RELEASE message
|
|
*---------------------------------------------------------------------------*/
|
|
void
|
|
i4b_l3_tx_release(call_desc_t *cd, int send_cause_flag)
|
|
{
|
|
struct l2_softc *l2sc = (l2_softc_t*)cd->l3drv->l1_token;
|
|
struct mbuf *m;
|
|
u_char *ptr;
|
|
int len = I_FRAME_HDRLEN + MSG_RELEASE_LEN;
|
|
|
|
NDBGL3(L3_PRIM, "isdnif %d, cr = 0x%02x", cd->isdnif, cd->cr);
|
|
|
|
if(send_cause_flag == 0)
|
|
len -= 4;
|
|
|
|
if((m = i4b_Dgetmbuf(len)) == NULL)
|
|
panic("i4b_l3_tx_release: can't allocate mbuf");
|
|
|
|
ptr = m->m_data + I_FRAME_HDRLEN;
|
|
|
|
*ptr++ = PD_Q931; /* protocol discriminator */
|
|
*ptr++ = 0x01; /* call reference length */
|
|
*ptr++ = setup_cr(cd, cd->cr); /* call reference value */
|
|
*ptr++ = RELEASE; /* message type = release complete */
|
|
|
|
if(send_cause_flag)
|
|
{
|
|
*ptr++ = IEI_CAUSE; /* cause ie */
|
|
*ptr++ = CAUSE_LEN;
|
|
*ptr++ = CAUSE_STD_LOC_OUT;
|
|
*ptr++ = make_q931_cause(cd->cause_out);
|
|
}
|
|
|
|
i4b_dl_data_req(l2sc, l2sc->drv, m);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* send ALERTING message
|
|
*---------------------------------------------------------------------------*/
|
|
void
|
|
i4b_l3_tx_alert(call_desc_t *cd)
|
|
{
|
|
struct l2_softc *l2sc = (l2_softc_t*)cd->l3drv->l1_token;
|
|
struct mbuf *m;
|
|
u_char *ptr;
|
|
|
|
if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_ALERT_LEN)) == NULL)
|
|
panic("i4b_l3_tx_alert: can't allocate mbuf");
|
|
|
|
NDBGL3(L3_PRIM, "isdnif %d, cr = 0x%02x", cd->isdnif, cd->cr);
|
|
|
|
ptr = m->m_data + I_FRAME_HDRLEN;
|
|
|
|
*ptr++ = PD_Q931; /* protocol discriminator */
|
|
*ptr++ = 0x01; /* call reference length */
|
|
*ptr++ = setup_cr(cd, cd->cr); /* call reference value */
|
|
*ptr++ = ALERT; /* message type = alert */
|
|
|
|
i4b_dl_data_req(l2sc, l2sc->drv, m);
|
|
}
|
|
|
|
#endif /* NI4BQ931 > 0 */
|