mirror of https://github.com/sipwise/sems.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
665 lines
27 KiB
665 lines
27 KiB
#include "AmApi.h"
|
|
//#include "GWCall.h"
|
|
#include "globals.h"
|
|
#include "GatewayFactory.h"
|
|
#include "mISDNChannel.h"
|
|
#include "mISDNNames.h"
|
|
#include "amci/codecs.h"
|
|
#include <math.h>
|
|
|
|
using namespace mISDN;
|
|
|
|
//we need to swap bits in bytes for isdn audio. this 2 functions are borowed from asterisk
|
|
char flip_table[256];
|
|
void init_flip_bits(void) {
|
|
int i,k;
|
|
for (i = 0 ; i < 256 ; i++) {
|
|
unsigned char sample = 0 ;
|
|
for (k = 0; k<8; k++) {
|
|
if ( i & 1 << k ) sample |= 0x80 >> k;
|
|
}
|
|
flip_table[i] = sample;
|
|
}
|
|
}
|
|
static char * flip_buf_bits ( char * buf , int len) {
|
|
int i;
|
|
char * start = buf;
|
|
for (i = 0 ; i < len; i++) {
|
|
buf[i] = flip_table[(unsigned char)buf[i]];
|
|
}
|
|
return start;
|
|
}
|
|
|
|
/* First AmAudio interface This is short. */
|
|
int mISDNChannel::read(unsigned int user_ts, unsigned int size) {
|
|
// DBG("mISDNChannel::read user_ts=%d size=%d buffersize=%d\n",user_ts,size,fromISDN_buffer.size());
|
|
//i know this is not fastest implementation but its short and works
|
|
fromISDN_buffer.copy((char *)((unsigned char*)samples),size);
|
|
fromISDN_buffer.erase(0,size);
|
|
return size;
|
|
}
|
|
int mISDNChannel::write(unsigned int user_ts, unsigned int size) {
|
|
char buf[4096+mISDN_HEADER_LEN];
|
|
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
|
|
int ret;
|
|
// DBG("mISDNChannel::write user_ts=%d size=%d\n",user_ts,size);
|
|
if(m_BC==0) {
|
|
// DBG("bchannel is already detached or not yet initialised\n"); //we silently discard this to avoid log flooding
|
|
return 0;
|
|
}
|
|
if(size>=4096) {
|
|
DBG("truncating output audio (%d)\n",size);
|
|
size=4096;
|
|
}
|
|
memcpy(buf + (mISDN_HEADER_LEN), (unsigned char*)samples, size);
|
|
flip_buf_bits( buf + mISDN_HEADER_LEN, size);
|
|
frame->addr = m_BC | FLG_MSG_DOWN;
|
|
frame->prim = DL_DATA | REQUEST;
|
|
frame->dinfo = 0;
|
|
frame->len = size;
|
|
ret = mISDN::mISDN_write(mISDNStack::instance()->m_mISDNdevice, buf, frame->len+mISDN_HEADER_LEN, 8000);
|
|
// DBG("mISDNChannel::write: sending packet directly to isdn 0x%x 0x%x %d ret=%d\n",frame->addr, frame->prim,frame->len,ret);
|
|
return ret;
|
|
}
|
|
void mISDNChannel::bchan_receive(char *msg_buf,int msg_buf_s) {
|
|
int len=msg_buf_s-mISDN_HEADER_LEN;
|
|
std::string tmp;
|
|
// DBG("mISDNChannel::bchannel_receive size=%d buffersize=%d\n",msg_buf_s - mISDN_HEADER_LEN,fromISDN_buffer.size());
|
|
flip_buf_bits( msg_buf + mISDN_HEADER_LEN, len);
|
|
tmp.assign(msg_buf + mISDN_HEADER_LEN,len);
|
|
fromISDN_buffer.append(tmp);
|
|
return;
|
|
}
|
|
//void mISDNChannel::bchannel_send() {
|
|
// char buf[PLAY_SIZE+mISDN_HEADER_LEN];
|
|
// mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
|
|
// int l,ret;
|
|
// int i,t;
|
|
// char *s;
|
|
//
|
|
// flip_buf_bits( buf + mISDN_HEADER_LEN, PLAY_SIZE);
|
|
// frame->addr = m_BC | FLG_MSG_DOWN;
|
|
// frame->prim = DL_DATA | REQUEST;
|
|
// frame->dinfo = 0;
|
|
// frame->len = PLAY_SIZE;
|
|
// ret = mISDN::mISDN_write(mISDNStack::instance()->m_mISDNdevice, buf, PLAY_SIZE+mISDN_HEADER_LEN, 8000);
|
|
// DBG("mISDNChannel::bchannel_send write=%d\n",ret);
|
|
// return;
|
|
//}
|
|
|
|
|
|
//some code borrowed from Linux Call Router
|
|
static signed char _mISDN_l3_ie2pos[128] = {
|
|
-1,-1,-1,-1, 0,-1,-1,-1, 1,-1,-1,-1,-1,-1,-1,-1,
|
|
2,-1,-1,-1, 3,-1,-1,-1, 4,-1,-1,-1, 5,-1, 6,-1,
|
|
7,-1,-1,-1,-1,-1,-1, 8, 9,10,-1,-1,11,-1,-1,-1,
|
|
-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
13,-1,14,15,16,17,18,19,-1,-1,-1,-1,20,21,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,22,23,-1,-1,
|
|
24,25,-1,-1,26,-1,-1,-1,27,28,-1,-1,29,30,31,-1
|
|
};
|
|
|
|
/*
|
|
static unsigned char _mISDN_l3_pos2ie[32] = {
|
|
0x04, 0x08, 0x10, 0x14, 0x18, 0x1c, 0x1e, 0x20,
|
|
0x27, 0x28, 0x29, 0x2c, 0x34, 0x40, 0x42, 0x43,
|
|
0x44, 0x45, 0x46, 0x47, 0x4c, 0x4d, 0x6c, 0x6d,
|
|
0x70, 0x71, 0x74, 0x78, 0x79, 0x7c, 0x7d, 0x7e
|
|
};
|
|
*/
|
|
|
|
int mISDN_get_free_ext_ie(mISDN::Q931_info_t *qi) {
|
|
int i;
|
|
for (i = 0; i < 8; i++) {
|
|
if (qi->ext[i].ie.off == 0)
|
|
return(i);
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
int mISDN_AddIE(mISDN::Q931_info_t *qi, u_char *p, u_char ie, u_char *iep) {
|
|
u_char *ps;
|
|
mISDN::ie_info_t *ies;
|
|
int l;
|
|
|
|
if (ie & 0x80) { /* one octett IE */
|
|
if (ie == IE_MORE_DATA)
|
|
ies = &qi->more_data;
|
|
else if (ie == IE_COMPLETE)
|
|
ies = &qi->sending_complete;
|
|
else if ((ie & 0xf0) == IE_CONGESTION)
|
|
ies = &qi->congestion_level;
|
|
else {
|
|
return(-1);
|
|
}
|
|
l = 0;
|
|
} else {
|
|
if (!iep || !iep[0])
|
|
return(-3);
|
|
ies = &qi->bearer_capability;
|
|
if (_mISDN_l3_ie2pos[ie]<0) {
|
|
return(-2);
|
|
}
|
|
ies += _mISDN_l3_ie2pos[ie];
|
|
if (ies->off) {
|
|
while (ies->repeated)
|
|
ies = &qi->ext[ies->ridx].ie;;
|
|
l = mISDN_get_free_ext_ie(qi);
|
|
if (l < 0) { // overflow
|
|
return(-3);
|
|
}
|
|
ies->ridx = l;
|
|
ies->repeated = 1;
|
|
ies = &qi->ext[l].ie;
|
|
ies->cs_flg = 0;
|
|
qi->ext[l].v.codeset = 0;
|
|
qi->ext[l].v.val = ie;
|
|
}
|
|
l = iep[0] + 1;
|
|
}
|
|
ps = (u_char *) qi;
|
|
ps += L3_EXTRA_SIZE;
|
|
ies->off = (u16)(p - ps);
|
|
*p++ = ie;
|
|
if (l)
|
|
memcpy(p, iep, l);
|
|
return(l+1);
|
|
}
|
|
|
|
|
|
mISDNChannel::mISDNChannel() : AmAudio(new AmAudioSimpleFormat(CODEC_ALAW)){
|
|
DBG("this is temporary constructor\n");
|
|
init();
|
|
m_port=mISDNStack::instance()->mISDNport_first;
|
|
}
|
|
|
|
mISDNChannel::mISDNChannel(mISDNport *port) : AmAudio(new AmAudioSimpleFormat(CODEC_ALAW)){
|
|
init();
|
|
m_port=port;
|
|
}
|
|
|
|
mISDNChannel::~mISDNChannel() {
|
|
unregister_CR();
|
|
unregister_BC();
|
|
DBG("mISDNChannel destructor ends\n");
|
|
}
|
|
void mISDNChannel::init() {
|
|
|
|
m_frame=(mISDN::iframe_t*)m_last_msg;
|
|
m_qi = (mISDN::Q931_info_t*)(m_last_msg + mISDN_HEADER_LEN);
|
|
m_ie_data =(char *)m_qi + L3_EXTRA_SIZE;
|
|
/* init the audio buffers for in&out */
|
|
// pthread_mutex_init(&fromISDN_lock, NULL);
|
|
// pthread_mutex_init(&toISDN_lock, NULL);
|
|
fromISDN_buffer.assign("");
|
|
}
|
|
|
|
void mISDNChannel::setSession(GWSession* session) {
|
|
m_session = session;
|
|
}
|
|
GWSession* mISDNChannel::getSession() {
|
|
return m_session;
|
|
}
|
|
|
|
void mISDNChannel::unregister_CR() {
|
|
mISDNStack* stack=mISDNStack::instance();
|
|
std::map<int,mISDNChannel*>::iterator CR_iter=stack->CR_map.find(m_CR);;
|
|
if(CR_iter==stack->CR_map.end()) {
|
|
DBG("mISDNChannel::unregister_CR Cant find myself in CR_map this=%p (0x%08x)\n",this,m_CR);
|
|
} else {
|
|
DBG("mISDNChannel::unregister_CR removing channel from CR_map this=%p (0x%08x)\n",this,m_CR);
|
|
stack->CR_map.erase(CR_iter);
|
|
}
|
|
m_CR=0;
|
|
}
|
|
void mISDNChannel::unregister_BC() {
|
|
mISDNStack* stack=mISDNStack::instance();
|
|
if(m_BC!=0) {
|
|
std::map<int,mISDNChannel*>::iterator BC_iter=stack->BC_map.find(m_BC&STACK_ID_MASK);;
|
|
if(BC_iter==stack->BC_map.end()) {
|
|
DBG("mISDNChannel::unregister_BC Cant find myself in BC_map %p (0x%08x)\n",this,m_BC);
|
|
} else {
|
|
DBG("mISDNChannel::unregister_BC is removing channel from BC_map this=%p (0x%08x)\n",this,m_BC);
|
|
stack->BC_map.erase(BC_iter);
|
|
}
|
|
m_BC=0;
|
|
} else DBG("mISDNChannel::unregister_BC BC already removed or not initialized, this=%p (0x%08x)\n",this,m_BC);
|
|
}
|
|
|
|
int mISDNChannel::placeCall(const AmSipRequest &req, std::string tonumber, std::string fromnumber) {
|
|
m_called=tonumber;
|
|
m_TON_d=0; //Unknown
|
|
m_NPI_d=1; // ISDN E.164
|
|
if(fromnumber.empty()) {
|
|
m_caller=gwconf.getParameter("out_msn","");
|
|
} else
|
|
m_caller=fromnumber;
|
|
m_TON_r=0; //Unknown
|
|
m_NPI_r=1; // ISDN E.164
|
|
m_Screening_r=0; // user provided
|
|
m_Presentation_r=0; // allowed
|
|
return call();
|
|
|
|
}
|
|
int mISDNChannel::accept() {
|
|
mISDNStack* stack=mISDNStack::instance();
|
|
char buf[MAX_MSG_SIZE];
|
|
// mISDN::Q931_info_t *qi;
|
|
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
|
|
DBG("mISDNChannel::accept\n");
|
|
frame->prim = CC_CONNECT | REQUEST;
|
|
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
|
|
frame->dinfo= m_CR;
|
|
frame->len= 0;
|
|
DBG("Sending CC_CONNECT | REQUEST for CR=0x%04x \n",m_CR);
|
|
mISDN::mISDN_write(stack->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int mISDNChannel::hangup() {
|
|
mISDNStack* stack=mISDNStack::instance();
|
|
char buf[MAX_MSG_SIZE];
|
|
// mISDN::Q931_info_t *qi;
|
|
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
|
|
|
|
DBG("mISDNChannel::hangup\n");
|
|
frame->prim = CC_DISCONNECT | REQUEST;
|
|
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
|
|
frame->dinfo= m_CR;
|
|
frame->len= 0;
|
|
DBG("Sending CC_DISCONNECT | REQUEST for CR=0x%04x \n",m_CR);
|
|
mISDN::mISDN_write(stack->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int mISDNChannel::call() {
|
|
mISDNStack* stack=mISDNStack::instance();
|
|
unsigned char buf[MAX_MSG_SIZE], *p, *msg, ie[64];
|
|
mISDN::Q931_info_t *qi;
|
|
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
|
|
int ret;
|
|
size_t i;
|
|
|
|
INFO("mISDN is making outbound call from %s to %s\n", m_caller.c_str(), m_called.c_str());
|
|
//making new isdn call ref
|
|
m_CR=stack->GenerateCR();
|
|
frame->prim = CC_NEW_CR | REQUEST;
|
|
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
|
|
frame->dinfo= m_CR;
|
|
frame->len=0;
|
|
DBG("sending CC_NEW_CR | REQUEST to device=%d addr=0x%08x dinfo=0x%08x\n",mISDNStack::instance()->m_mISDNdevice,frame->addr,frame->dinfo);
|
|
ret=mISDN::mISDN_write(mISDNStack::instance()->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
|
|
if ( ret<0) {
|
|
ERROR("mISDNChannel::call error on NEW_CR | REQUEST %d\n", ret);
|
|
return FAIL;
|
|
}
|
|
stack->CR_map[m_CR]=this;
|
|
DBG("Adding self (%p) to channel_map my CR=0x%08x \n",this,m_CR);
|
|
p = msg = buf + mISDN_HEADER_LEN;
|
|
qi = (mISDN::Q931_info_t *)p;
|
|
memset(qi, 0, sizeof(mISDN::Q931_info_t));
|
|
qi->type = MT_SETUP;
|
|
p += L3_EXTRA_SIZE;
|
|
p++; /* needed to avoid offset 0 in IE array */
|
|
ret = mISDN_AddIE(qi, p, IE_COMPLETE, NULL);
|
|
if ( ret<0) {
|
|
ERROR("mISDNChannel::call Add IE_COMPLETE error %d\n", ret);
|
|
return FAIL;
|
|
}
|
|
p += ret;
|
|
ret = mISDN_AddIE(qi, p, IE_BEARER, (unsigned char*)"\x3\x90\x90\xa3"); /* Audio */
|
|
// ret = mISDN_AddIE(qi, p, IE_BEARER, (unsigned char*)"\x2\x88\x90"); /* default Datatransmission 64k */
|
|
if (ret<0) { ERROR("mISDNChannel::call Add IE_BEARER error %d\n", ret); return FAIL;}
|
|
p += ret;
|
|
ie[0] = m_caller.size() + 1;
|
|
ie[1] = 0x00 + (m_TON_r << 4) + m_NPI_r; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
|
|
if (m_Presentation_r >= 0) {
|
|
ie[1] = 0x00 + (m_TON_r<<4) + m_NPI_r;
|
|
ie[2] = 0x80 + (m_Presentation_r<<5) + m_Screening_r;
|
|
for (i=0; i<=m_caller.size(); i++)
|
|
ie[3+i] = m_caller[i] & 0x7f;
|
|
} else {
|
|
ie[1] = 0x80 + (m_TON_r<<4) + m_NPI_r;
|
|
for (i=0; i<=m_caller.size(); i++)
|
|
ie[2+i] = m_caller[i] & 0x7f;
|
|
}
|
|
ret = mISDN_AddIE(qi, p, IE_CALLING_PN, ie);
|
|
if (ret<0) { ERROR("mISDNChannel::call Add IE_CALLING_PN error %d\n", ret);return FAIL; }
|
|
p += ret;
|
|
ie[0] =m_called.size() + 1;
|
|
ie[1] = 0x80 + (m_TON_d << 4) + m_NPI_d; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
|
|
for (i=0; i<=m_called.size(); i++)
|
|
ie[2+i] = m_called[i] & 0x7f;
|
|
ret = mISDN_AddIE(qi, p, IE_CALLED_PN, ie);
|
|
if (ret<0) { ERROR("mISDNChannel::call Add IE_CALLED_PN error %d\n", ret);return FAIL; }
|
|
p += ret;
|
|
frame->prim = CC_SETUP | REQUEST;
|
|
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
|
|
frame->dinfo= m_CR;
|
|
frame->len= p - msg;
|
|
ret=mISDN::mISDN_write(mISDNStack::instance()->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
|
|
if ( ret<0) {
|
|
ERROR("mISDNChannel::call error dending CC_SETUP | REQUEST %d\n", ret);
|
|
return FAIL;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
int mISDNChannel::processMsg(char *msg_buf,int msg_buf_s) {
|
|
mISDNStack* stack=mISDNStack::instance();
|
|
char buf[MAX_MSG_SIZE];
|
|
// mISDN::Q931_info_t *qi;
|
|
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
|
|
char *p;
|
|
|
|
p=(char *)&m_last_msg;
|
|
memcpy(p, msg_buf, msg_buf_s);
|
|
m_last_msg_s=msg_buf_s;
|
|
memset(p+msg_buf_s,0,MAX_MSG_SIZE-msg_buf_s);
|
|
switch(m_frame->prim) {
|
|
case CC_SETUP |INDICATION:
|
|
DBG("CC_SETUP | INDICATION for CR=0x%04x \n",m_CR);
|
|
GetIEchannel_id();
|
|
DBG("Creating Bchannel for CR=0x%04x \n",m_CR);
|
|
bchan_create();
|
|
GetCallerNum();
|
|
GetCalledNum();
|
|
m_session=GWSession::CallFromOutside(m_caller, m_called, 0, this);
|
|
if(m_session!=NULL) {
|
|
unsigned char buf[MAX_MSG_SIZE];
|
|
// mISDN::Q931_info_t *qi;
|
|
mISDN::iframe_t *frame = (mISDN::iframe_t *)buf;
|
|
int ret;
|
|
frame->prim = CC_PROCEEDING | REQUEST;
|
|
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
|
|
frame->dinfo= m_CR;
|
|
frame->len= 0;
|
|
ret=mISDN::mISDN_write(mISDNStack::instance()->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
|
|
DBG("m_session=%p Not null sending CC_PROCEEDING |REQUEST\n",m_session);
|
|
}
|
|
break;
|
|
case CC_PROCEEDING |INDICATION:
|
|
DBG("CC_PROCEEDING | INDICATION for CR=0x%04x \n",m_CR);
|
|
// m_session->acceptAudio(m_session->invite_req.body,m_req.hdrs,&sdp_reply);
|
|
// m_session->dlg.reply(m_session->invite_req,180, "Isdn side state is: PROCEEDING", "application/sdp",sdp_reply);
|
|
m_session->dlg.reply(m_session->invite_req,180, "Isdn side state is: PROCEEDING");
|
|
DBG("check 2 CC_PROCEEDING | INDICATION for CR=0x%04x \n",m_CR);
|
|
GetIEchannel_id();
|
|
DBG("Creating Bchannel for CR=0x%04x \n",m_CR);
|
|
bchan_create();
|
|
break;
|
|
case CC_ALERTING | INDICATION:
|
|
DBG("CC_ALERTING | INDICATION for CR=0x%04x \n",m_CR);
|
|
// m_session->acceptAudio(m_session->invite_req.body,m_req.hdrs,&sdp_reply);
|
|
// m_session->dlg.reply(m_session->invite_req,183, "Isdn side state is: ALERTING", "application/sdp",sdp_reply);
|
|
m_session->dlg.reply(m_session->invite_req,183, "Isdn side state is: ALERTING");
|
|
break;
|
|
case CC_CONNECT | INDICATION:
|
|
case CC_CONNECT_ACKNOWLEDGE | INDICATION:
|
|
DBG("CC_CONNECT(_ACKNOWLEDGE) | INDICATION for CR=0x%04x \n",m_CR);
|
|
DBG("Activating Bchannel for CR=0x%04x \n",m_CR);
|
|
bchan_activate();
|
|
m_session->onSessionStart(m_session->invite_req);
|
|
break;
|
|
case CC_DISCONNECT | INDICATION:
|
|
case CC_DISCONNECT | CONFIRM:
|
|
DBG("CC_DISCONNECT | INDICATION or CONFIRMfor CR=0x%04x \n",m_CR);
|
|
m_session->setInOut(NULL,NULL);
|
|
m_session->setStopped();
|
|
if(m_session->dlg.getStatus()==AmSipDialog::Pending) {
|
|
DBG("Sip side not yet connected sending reply\n");
|
|
m_session->dlg.reply(m_session->invite_req,487, "Isdn side state is: DISCONNECTING");
|
|
//maybe this would be better
|
|
// throw AmSession::Exception(487, "call terminated");
|
|
} else {
|
|
DBG("Sip side already connected sending bye\n");
|
|
m_session->dlg.bye();
|
|
}
|
|
// mISDN::mISDN_write_frame(stack->m_mISDNdevice, buf, m_port->upper_id | FLG_MSG_DOWN, CC_RELEASE | REQUEST, m_CR, 0, NULL, TIMEOUT_1SEC);
|
|
frame->prim = CC_RELEASE | REQUEST;
|
|
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
|
|
frame->dinfo= m_CR;
|
|
frame->len= 0;
|
|
DBG("Sending CC_RELEASE | REQUEST for CR=0x%04x \n",m_CR);
|
|
mISDN::mISDN_write(stack->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
|
|
bchan_deactivate();
|
|
break;
|
|
case CC_RELEASE | INDICATION:
|
|
case CC_RELEASE_COMPLETE | INDICATION:
|
|
DBG("CC_RELEASE(_COMPLETE) | INDICATION for CR=0x%04x \n",m_CR);
|
|
// mISDN::mISDN_write_frame(stack->m_mISDNdevice, buf, m_port->upper_id | FLG_MSG_DOWN, CC_RELEASE_COMPLETE | REQUEST, m_CR, 0, NULL, TIMEOUT_1SEC);
|
|
frame->prim = CC_RELEASE_COMPLETE| REQUEST;
|
|
frame->addr = m_port->upper_id | FLG_MSG_DOWN;
|
|
frame->dinfo= m_CR;
|
|
frame->len= 0;
|
|
DBG("Sending CC_RELEASE_COMPLETE | REQUEST for CR=0x%04x \n",m_CR);
|
|
mISDN::mISDN_write(stack->m_mISDNdevice, buf, mISDN_HEADER_LEN+frame->len, TIMEOUT_1SEC);
|
|
bchan_destroy();
|
|
break;
|
|
default:
|
|
ERROR("mISDNChannel::processMsg unhandled: prim(0x%x) addr(0x%x) msg->len(%d)\n", m_frame->prim, m_frame->addr, msg_buf_s);
|
|
return FAIL;
|
|
break;
|
|
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
int mISDNChannel::GetIEchannel_id(){
|
|
char *p;
|
|
m_bchannel=-1; //no ie or error (for now)
|
|
|
|
if (m_qi->channel_id.off==0) { ERROR("No channel_id IE here\n"); return FAIL; }
|
|
p = m_ie_data + m_qi->channel_id.off;
|
|
//p[0] is 0x18 - code for this ie;
|
|
DBG("mISDNChannel::GetIEchannel_id p= 0x%02hhx 0x%02hhx 0x%02hhx\n",p[0],p[1],p[2]);
|
|
if(p[1]<1) { ERROR("IE Too short\n"); return FAIL; }
|
|
if(p[2] & 0x40) { ERROR("Channels on other interfaces not supported\n"); return FAIL; } // bit 7 - other interface
|
|
if(p[2] & 0x04) { ERROR("using d-channel not supported\n"); return FAIL; } // bit 3 - d channel;
|
|
if(m_port->pri) {
|
|
switch((p[2]&0x03)) {
|
|
case 0: m_bchannel=-2; return OK; break; //no Channel
|
|
case 1: break; //channel num in folowing bytes
|
|
case 2: ERROR("Reserved bit set\n"); return FAIL; break; // reserver bit;
|
|
case 3: m_bchannel=-3; return OK; break; //ANY channel
|
|
}
|
|
if(p[1] < 3) { ERROR("IE Too short for PRI\n"); return FAIL; } // we need extended info on channel num for pri
|
|
if(p[3] & 0x10) { ERROR("channel map not supported\n"); return FAIL; } // bit 3 - d channel;
|
|
m_bchannel=p[4]&0x7f;
|
|
if(m_bchannel<1 || m_bchannel==16) {
|
|
ERROR("PRI channel out of range (%d)\n",m_bchannel);
|
|
m_bchannel=-1;
|
|
return FAIL;
|
|
}
|
|
DBG("mISDNChannel::GetIEchannel_id will use PRI b_channel=%d\n",m_bchannel);
|
|
return OK;
|
|
} else { //BRI
|
|
if ((p[2] & 0x20)) { ERROR("req for bri channel on PRI interface\n"); return FAIL; } // bit 6 - 0=BRI, 1-other(PRI);
|
|
switch((p[2]&0x03)) {
|
|
case 0: m_bchannel=-2; break; //no Channel
|
|
case 1: m_bchannel=1; break; //channel 1
|
|
case 2: m_bchannel=2; break; //channel 2
|
|
case 3: m_bchannel=-3; break; //ANY channel
|
|
}
|
|
DBG("mISDNChannel::GetIEchannel_id will use BRI b_channel=%d\n",m_bchannel);
|
|
return OK;
|
|
}
|
|
}
|
|
int mISDNChannel::GetCallerNum(){
|
|
char *p;
|
|
int len;
|
|
|
|
if (m_qi->calling_nr.off==0) { ERROR("No calling_nr IE here\n"); return FAIL; }
|
|
p = m_ie_data + m_qi->calling_nr.off;
|
|
//p[0] is 0x6C - code for this ie;
|
|
DBG("mISDNChannel::GetCallerNum p= 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx\n",p[0],p[1],p[2],p[3]);
|
|
p++;//now we scan each byte as some are optional
|
|
if(p[0]<1) { ERROR("IE Too short\n"); return FAIL; }
|
|
if(p[0]>=MAX_NUM_LEN-1) { ERROR("Number too long for MAX_NUM_LEN \n"); return FAIL; }
|
|
len=p[0];
|
|
p++;
|
|
m_TON_r=(p[0]&0x70)>>4;
|
|
m_NPI_r=p[0]&0x0F;
|
|
if(!(p[0]&80)) { //if this is not last byte
|
|
len--;p++; //warning p is shifted here to next byte (optional Presentation/Screening)
|
|
m_Presentation_r=(p[0]&0x60)>>5;
|
|
m_Screening_r=p[0]&0x03;
|
|
} else DBG("mISDNChannel::GetCallerNum no Presentation/Screening byte\n");
|
|
len--;p++;
|
|
DBG("mISDNChannel::GetCallerNum len=%d TON=%d NPI=%d Presentation=%d Screening=%d\n",len,m_TON_r,m_NPI_r,m_Presentation_r,m_Screening_r);
|
|
// memcpy(&m_caller, p, len);
|
|
// m_caller[len]='\0';
|
|
m_caller.assign(p,len);
|
|
DBG("mISDNChannel::GetCallerNum %s %s %s %s %s\n",m_caller.c_str(),mISDNNames::TON(m_TON_r),mISDNNames::NPI(m_NPI_r),mISDNNames::Presentation(m_Presentation_r),mISDNNames::Screening(m_Screening_r));
|
|
return OK;
|
|
}
|
|
int mISDNChannel::GetCalledNum(){
|
|
char *p;
|
|
int len;
|
|
|
|
if (m_qi->called_nr.off==0) { ERROR("No called_nr IE here\n"); return FAIL; }
|
|
p = m_ie_data + m_qi->called_nr.off;
|
|
//p[0] is 0x70 - code for this ie;
|
|
DBG("mISDNChannel::GetCalledNum p= 0x%02hhx 0x%02hhx 0x%02hhx\n",p[0],p[1],p[2]);
|
|
if(p[1]<1) { ERROR("IE Too short\n"); return FAIL; }
|
|
if(p[1]>=MAX_NUM_LEN-1) { ERROR("Number too long for MAX_NUM_LEN \n"); return FAIL; }
|
|
len=p[1];
|
|
m_TON_d=(p[2]&0x70)>>4;
|
|
m_NPI_d=p[2]&0x0F;
|
|
DBG("mISDNChannel::GetCalledNum len=%d TON=%d NPI=%d\n",len,m_TON_d,m_NPI_d);
|
|
// memcpy(&m_called, p+3, len-1);
|
|
// m_called[len-1]='\0';
|
|
m_called.assign(p+3,len-1);
|
|
DBG("mISDNChannel::GetCalledNum %s %s %s\n",m_called.c_str(),mISDNNames::TON(m_TON_d),mISDNNames::NPI(m_NPI_d));
|
|
return OK;
|
|
}
|
|
int mISDNChannel::bchan_event(char *msg_buf,int msg_buf_s) {
|
|
char *p;
|
|
|
|
p=(char *)&m_last_msg;
|
|
memcpy(p, msg_buf, msg_buf_s);
|
|
m_last_msg_s=msg_buf_s;
|
|
memset(p+msg_buf_s,0,MAX_MSG_SIZE-msg_buf_s);
|
|
switch(m_frame->prim) {
|
|
case PH_DATA | CONFIRM:
|
|
case DL_DATA | CONFIRM:
|
|
// DBG("PH_DATA or DL_DATA confirm prim(0x%x) addr(0x%x) msg->len(%d) \n", m_frame->prim, m_frame->addr, msg_buf_s);
|
|
// bchannel_send(); //we are now transmiting directly from Channel(AmAudio)::write
|
|
break;
|
|
case PH_DATA | INDICATION:
|
|
case DL_DATA | INDICATION:
|
|
// DBG("PH_DATA or DL_DATA IND prim(0x%x) addr(0x%x) msg->len(%d) \n", m_frame->prim, m_frame->addr, msg_buf_s);
|
|
bchan_receive(msg_buf,msg_buf_s);
|
|
break;
|
|
case PH_CONTROL | INDICATION:
|
|
case PH_SIGNAL | INDICATION:
|
|
DBG("PH_CONTROL or PH_SIGNAL IND prim(0x%x) addr(0x%x) msg->len(%d) \n", m_frame->prim, m_frame->addr, msg_buf_s);
|
|
break;
|
|
case PH_ACTIVATE | INDICATION:
|
|
case DL_ESTABLISH | INDICATION:
|
|
case PH_ACTIVATE | CONFIRM:
|
|
case DL_ESTABLISH | CONFIRM:
|
|
DBG("(PH|DL)_(ESTABLISH|ACTIVATE (IND|CONFIRM): bchannel is now activated (address 0x%x).\n", m_frame->addr);
|
|
break;
|
|
case PH_DEACTIVATE | INDICATION:
|
|
case DL_RELEASE | INDICATION:
|
|
case PH_DEACTIVATE | CONFIRM:
|
|
case DL_RELEASE | CONFIRM:
|
|
DBG("(PH|DL)_(RELEASE|DEACTIVATE (IND|CONFIRM): bchannel is now de-activated (address 0x%x).\n", m_frame->addr);
|
|
bchan_destroy();
|
|
unregister_BC();
|
|
break;
|
|
default:
|
|
ERROR("child message not handled: prim(0x%x) addr(0x%x) msg->len(%d)\n", m_frame->prim, m_frame->addr, msg_buf_s);
|
|
return FAIL;
|
|
break;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
int mISDNChannel::bchan_create() {
|
|
layer_info_t li;
|
|
mISDN_pid_t pid;
|
|
int ret;
|
|
mISDNStack* stack=mISDNStack::instance();
|
|
|
|
if(m_bchannel<=0) { ERROR("b-channel num not known or invalid (%d)\n",m_bchannel); return FAIL; }
|
|
if(m_port->b_stid[m_bchannel-1]==0) { ERROR("No stack for b-channel (%d)\n",m_bchannel); return FAIL; }
|
|
if(m_port->b_addr[m_bchannel-1]!=0) { ERROR("Stack already created for b-channel (%d)\n",m_bchannel); return FAIL; }
|
|
memset(&li, 0, sizeof(li));
|
|
memset(&pid, 0, sizeof(pid));
|
|
li.object_id = -1;
|
|
li.extentions = 0;
|
|
li.st = m_port->b_stid[m_bchannel-1];
|
|
strcpy(li.name, "B L4");
|
|
// li.pid.layermask = ISDN_LAYER((4));
|
|
li.pid.layermask = ISDN_LAYER((3));
|
|
// li.pid.protocol[4] = ISDN_PID_L4_B_USER;
|
|
li.pid.protocol[3] = ISDN_PID_L3_B_TRANS;
|
|
ret = mISDN_new_layer(mISDNStack::instance()->m_mISDNdevice, &li);
|
|
if(ret || !li.id) { ERROR("mISDN_new_layer() failed to add bchannel %d\n", m_bchannel); return FAIL; }
|
|
m_BC=m_port->b_addr[m_bchannel-1]=li.id;
|
|
pid.protocol[1] = ISDN_PID_L1_B_64TRANS;
|
|
pid.protocol[2] = ISDN_PID_L2_B_TRANS;
|
|
pid.protocol[3] = ISDN_PID_L3_B_TRANS;
|
|
// pid.protocol[3] = ISDN_PID_L3_B_DSP;
|
|
// pid.protocol[4] = ISDN_PID_L4_B_USER;
|
|
pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) ;
|
|
// pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) | ISDN_LAYER((4));
|
|
ret = mISDN_set_stack(stack->m_mISDNdevice, m_port->b_stid[m_bchannel-1], &pid);
|
|
if(ret) { ERROR("mISDN_set_stack failed to add bchannel %d\n", m_bchannel); return FAIL; }
|
|
ret = mISDN_get_setstack_ind(stack->m_mISDNdevice, m_BC);
|
|
if(ret) { ERROR("mISDN_set_stack_ind failed to add bchannel %d\n", m_bchannel); return FAIL; }
|
|
m_BC=m_port->b_addr[m_bchannel-1]=mISDN_get_layerid(stack->m_mISDNdevice, m_port->b_stid[m_bchannel-1], 3);
|
|
// m_BC=m_port->b_addr[m_bchannel-1]=mISDN_get_layerid(stack->m_mISDNdevice, m_port->b_stid[m_bchannel-1], 4);
|
|
if(m_BC==0) { ERROR("mISDN_get_layerid failed to add bchannel %d\n", m_bchannel); return FAIL; }
|
|
stack->BC_map[m_BC&STACK_ID_MASK]=this;
|
|
m_port->b_port[m_bchannel-1]=this;
|
|
DBG("Successfully created stack for port %d. addr=0x%08x\n",m_bchannel,m_BC);
|
|
return OK;
|
|
}
|
|
int mISDNChannel::bchan_activate() {
|
|
mISDN::iframe_t frame;
|
|
mISDNStack* stack=mISDNStack::instance();
|
|
int ret;
|
|
|
|
if(m_BC==0) { ERROR("bchannel (%d) not created\n",m_bchannel); return FAIL; }
|
|
DBG("sending DL_ESTABLISH | REQUEST to device=%d for bchannel=%d addr=0x%08x dinfo=0x%08x\n",stack->m_mISDNdevice, m_bchannel,frame.addr, frame.dinfo);
|
|
ret = mISDN::mISDN_write_frame(stack->m_mISDNdevice, &frame, m_BC | FLG_MSG_DOWN, DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
|
|
return OK;
|
|
}
|
|
int mISDNChannel::bchan_deactivate() {
|
|
mISDN::iframe_t frame;
|
|
mISDNStack* stack=mISDNStack::instance();
|
|
int ret;
|
|
|
|
DBG("sending DL_RELEASE | REQUEST to device=%d for bchannel=%d addr=0x%08x dinfo=0x%08x\n",stack->m_mISDNdevice, m_bchannel,frame.addr, frame.dinfo);
|
|
ret = mISDN::mISDN_write_frame(stack->m_mISDNdevice, &frame, m_BC | FLG_MSG_DOWN, DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
|
|
return OK;
|
|
}
|
|
|
|
int mISDNChannel::bchan_destroy() {
|
|
mISDN::iframe_t frame;
|
|
mISDNStack* stack=mISDNStack::instance();
|
|
int ret;
|
|
|
|
ret = mISDN_clear_stack(stack->m_mISDNdevice, m_port->b_stid[m_bchannel-1]);
|
|
DBG("sending MGR_DELLAYER | REQUEST to device=%d for bchannel=%d addr=0x%08x dinfo=0x%08x\n",stack->m_mISDNdevice, m_bchannel,frame.addr, frame.dinfo);
|
|
ret = mISDN::mISDN_write_frame(stack->m_mISDNdevice, &frame, m_BC | FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
|
|
unregister_BC();
|
|
m_port->b_port[m_bchannel-1]=NULL;
|
|
m_port->b_addr[m_bchannel-1]=0;
|
|
return OK;
|
|
}
|
|
|
|
|
|
/** EMACS **
|
|
* Local variables:
|
|
* mode: c++
|
|
* c-basic-offset: 4
|
|
* End:
|
|
*/
|