440779495a
git-svn-id: http://yate.null.ro/svn/yate/trunk@1817 acf43c95-373e-0410-b603-e72c3f656dc1
324 lines
8.9 KiB
C++
324 lines
8.9 KiB
C++
/**
|
|
* management.cpp
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
|
*
|
|
* Yet Another Signalling Stack - implements the support for SS7, ISDN and PSTN
|
|
*
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
|
* Copyright (C) 2004-2006 Null Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "yatesig.h"
|
|
|
|
|
|
using namespace TelEngine;
|
|
|
|
#define MAKE_NAME(x) { #x, SS7MsgSNM::x }
|
|
static const TokenDict s_snm_names[] = {
|
|
// this list must be kept in synch with the header
|
|
MAKE_NAME(COO),
|
|
MAKE_NAME(ECO),
|
|
MAKE_NAME(RCT),
|
|
MAKE_NAME(TFP),
|
|
MAKE_NAME(RST),
|
|
MAKE_NAME(RSP), // alias
|
|
MAKE_NAME(LIN),
|
|
MAKE_NAME(TRA),
|
|
MAKE_NAME(DLC),
|
|
MAKE_NAME(UPU),
|
|
MAKE_NAME(COA),
|
|
MAKE_NAME(ECA),
|
|
MAKE_NAME(TFC),
|
|
MAKE_NAME(TCP),
|
|
MAKE_NAME(TFPA), // alias
|
|
MAKE_NAME(RSR),
|
|
MAKE_NAME(LUN),
|
|
MAKE_NAME(TRW),
|
|
MAKE_NAME(CSS),
|
|
MAKE_NAME(TFR),
|
|
MAKE_NAME(RCP),
|
|
MAKE_NAME(LIA),
|
|
MAKE_NAME(CNS),
|
|
MAKE_NAME(TCR),
|
|
MAKE_NAME(RCR),
|
|
MAKE_NAME(LUA),
|
|
MAKE_NAME(CNP),
|
|
MAKE_NAME(CBD),
|
|
MAKE_NAME(TFA),
|
|
MAKE_NAME(LID),
|
|
MAKE_NAME(CBA),
|
|
MAKE_NAME(TCA),
|
|
MAKE_NAME(TFAA), // alias
|
|
MAKE_NAME(LFU),
|
|
MAKE_NAME(LLT),
|
|
MAKE_NAME(LLI), // alias
|
|
MAKE_NAME(LRT),
|
|
MAKE_NAME(LRI), // alias
|
|
{ 0, 0 }
|
|
};
|
|
|
|
static const TokenDict s_snm_group[] = {
|
|
// this list must be kept in synch with the header
|
|
MAKE_NAME(CHM),
|
|
MAKE_NAME(ECM),
|
|
MAKE_NAME(FCM),
|
|
MAKE_NAME(TFM),
|
|
MAKE_NAME(RSM),
|
|
MAKE_NAME(MIM),
|
|
MAKE_NAME(TRM),
|
|
MAKE_NAME(DLM),
|
|
MAKE_NAME(UFC),
|
|
{ 0, 0 }
|
|
};
|
|
#undef MAKE_NAME
|
|
|
|
|
|
// Constructor
|
|
SS7MsgSNM::SS7MsgSNM(unsigned char type)
|
|
: SignallingMessage(lookup((Type)type,"Unknown")),
|
|
m_type(type)
|
|
{
|
|
}
|
|
|
|
void SS7MsgSNM::toString(String& dest, const SS7Label& label, bool params) const
|
|
{
|
|
const char* enclose = "\r\n-----";
|
|
dest = enclose;
|
|
dest << "\r\n" << name() << " [label=" << label << ']';
|
|
if (params) {
|
|
unsigned int n = m_params.length();
|
|
for (unsigned int i = 0; i < n; i++) {
|
|
NamedString* s = m_params.getParam(i);
|
|
if (s)
|
|
dest << "\r\n " << s->name() << "='" << *s << "'";
|
|
}
|
|
}
|
|
dest << enclose;
|
|
}
|
|
|
|
// Parse a received buffer and build a message from it
|
|
SS7MsgSNM* SS7MsgSNM::parse(SS7Management* receiver, unsigned char type,
|
|
SS7PointCode::Type pcType, const unsigned char* buf, unsigned int len)
|
|
{
|
|
SS7MsgSNM* msg = new SS7MsgSNM(type);
|
|
#ifdef XDEBUG
|
|
String tmp;
|
|
tmp.hexify((void*)buf,len,' ');
|
|
Debug(receiver,DebugAll,"Decoding msg=%s pctype=%u buf: %s [%p]",
|
|
msg->name(),pcType,tmp.c_str(),receiver);
|
|
#endif
|
|
// TODO: parse the rest of the message. Check extra bytes (message specific)
|
|
if (!(buf && len))
|
|
return msg;
|
|
while (true) {
|
|
// TFP,TFR,TFA: Q.704 15.7 The must be at lease 2 bytes in buffer
|
|
if (type == TFP || type == TFR || type == TFA) {
|
|
// 2 bytes destination
|
|
SS7PointCode pc;
|
|
unsigned char spare;
|
|
if (pc.assign(pcType,buf,len,&spare)) {
|
|
String tmp;
|
|
tmp << pc;
|
|
msg->params().addParam("destination",tmp);
|
|
if (spare) {
|
|
tmp.hexify(&spare,1);
|
|
msg->params().addParam("spare",tmp);
|
|
}
|
|
}
|
|
else
|
|
Debug(receiver,DebugNote,
|
|
"Failed to decode destination for msg=%s len=%u [%p]",
|
|
msg->name(),len,receiver);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return msg;
|
|
}
|
|
|
|
const TokenDict* SS7MsgSNM::names()
|
|
{
|
|
return s_snm_names;
|
|
}
|
|
|
|
|
|
#define MAKE_NAME(x) { #x, SS7MsgMTN::x }
|
|
static const TokenDict s_mtn_names[] = {
|
|
// this list must be kept in synch with the header
|
|
MAKE_NAME(SLTM),
|
|
MAKE_NAME(SLTA),
|
|
{ 0, 0 }
|
|
};
|
|
#undef MAKE_NAME
|
|
|
|
const TokenDict* SS7MsgMTN::names()
|
|
{
|
|
return s_mtn_names;
|
|
}
|
|
|
|
|
|
bool SS7Management::receivedMSU(const SS7MSU& msu, const SS7Label& label, SS7Layer3* network, int sls)
|
|
{
|
|
if (msu.getSIF() != SS7MSU::SNM)
|
|
return false;
|
|
|
|
unsigned int len = msu.length() - label.length() - 1;
|
|
// according to Q.704 there should be at least the heading codes (8 bit)
|
|
const unsigned char* buf = msu.getData(label.length()+1,1);
|
|
if (!buf)
|
|
return false;
|
|
SS7MsgSNM* msg = SS7MsgSNM::parse(this,buf[0],label.type(),buf+1,len-1);
|
|
if (!msg)
|
|
return false;
|
|
|
|
if (debugAt(DebugInfo)) {
|
|
String tmp;
|
|
msg->toString(tmp,label,debugAt(DebugAll));
|
|
Debug(this,DebugInfo,"Received message (%p)%s",msg,tmp.c_str());
|
|
}
|
|
|
|
// TODO: implement
|
|
|
|
String l;
|
|
l << label;
|
|
if (msg->type() == SS7MsgSNM::TFP ||
|
|
msg->type() == SS7MsgSNM::TFR ||
|
|
msg->type() == SS7MsgSNM::TFA) {
|
|
String dest = msg->params().getValue("destination");
|
|
if (!dest.null()) {
|
|
if (debugAt(DebugInfo)) {
|
|
const char* status = (msg->type() == SS7MsgSNM::TFP) ? "prohibited" :
|
|
((msg->type() == SS7MsgSNM::TFA) ? "allowed" : "restricted");
|
|
Debug(this,DebugInfo,"%s (label=%s): Traffic is %s to dest=%s [%p]",
|
|
msg->name(),l.c_str(),status,dest.c_str(),this);
|
|
}
|
|
}
|
|
else
|
|
Debug(this,DebugNote,"Received %s (label=%s) without destination [%p]",
|
|
msg->name(),l.c_str(),this);
|
|
}
|
|
else if (msg->type() == SS7MsgSNM::TRA) {
|
|
String dest;
|
|
dest << label.opc();
|
|
Debug(this,DebugInfo,"%s (label=%s): Traffic can restart to dest=%s [%p]",
|
|
msg->name(),l.c_str(),dest.c_str(),this);
|
|
}
|
|
else {
|
|
String tmp;
|
|
tmp.hexify((void*)buf,len,' ');
|
|
String params;
|
|
unsigned int n = msg->params().count();
|
|
if (n)
|
|
for (unsigned int i = 0; i < n; i++) {
|
|
NamedString* ns = static_cast<NamedString*>(msg->params().getParam(i));
|
|
if (ns)
|
|
params.append(String(ns->name()) + "=" + *ns,",");
|
|
}
|
|
Debug(this,DebugMild,
|
|
"Unhandled SNM type=%s group=%s label=%s params:%s len=%u: %s ",
|
|
msg->name(),lookup(msg->group(),s_snm_group,"Spare"),
|
|
l.c_str(),params.c_str(),len,tmp.c_str());
|
|
}
|
|
|
|
TelEngine::destruct(msg);
|
|
return true;
|
|
}
|
|
|
|
void SS7Management::notify(SS7Layer3* network, int sls)
|
|
{
|
|
Debug(this,DebugStub,"Please implement SS7Management::notify(%p,%d) [%p]",
|
|
network,sls,this);
|
|
if (network && network->operational(sls)) {
|
|
// one link gone up - see MTP restart procedure (Q.704 - 9.1, 9.2)
|
|
// TODO: implement MTP restart procedure (Q.704 - 9.1, 9.2)
|
|
// for now just send a Traffic Restart Allowed
|
|
// FIXME: get point codes and network indicator from configuration
|
|
|
|
// Get local services attached to network
|
|
// Get destination routes from network
|
|
#if 0
|
|
SS7PointCode dpc(1,8,1);
|
|
SS7PointCode opc(1,8,2);
|
|
unsigned char sio = SS7MSU::National;
|
|
SS7PointCode::Type type = network->type(sio);
|
|
sio |= SS7MSU::SNM;
|
|
SS7Label lbl(type,dpc,opc,sls,0);
|
|
SS7MSU tra(sio,lbl,0,1);
|
|
unsigned char* d = tra.getData(lbl.length()+1,1);
|
|
d[0] = SS7MsgSNM::TRA;
|
|
transmitMSU(tra,lbl,sls);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
bool SS7Maintenance::receivedMSU(const SS7MSU& msu, const SS7Label& label, SS7Layer3* network, int sls)
|
|
{
|
|
if (msu.getSIF() != SS7MSU::MTN)
|
|
return false;
|
|
XDebug(this,DebugStub,"Possibly incomplete SS7Maintenance::receivedMSU(%p,%p,%p,%d) [%p]",
|
|
&msu,&label,network,sls,this);
|
|
|
|
unsigned int mlen = msu.length()-label.length()-1;
|
|
// Q.707 says test pattern length should be 1-15 but we accept 0 as well
|
|
const unsigned char* s = msu.getData(label.length()+1,2);
|
|
if (!s)
|
|
return false;
|
|
unsigned char len = s[1] >> 4;
|
|
// get a pointer to the test pattern
|
|
const unsigned char* t = msu.getData(label.length()+3,len);
|
|
if (!t) {
|
|
Debug(this,DebugMild,"Received MTN type %02X length %u with invalid pattern length %u [%p]",
|
|
s[0],msu.length(),len,this);
|
|
return false;
|
|
}
|
|
switch (s[0]) {
|
|
case SS7MsgMTN::SLTM:
|
|
{
|
|
Debug(this,DebugNote,"Received SLTM with test pattern length %u",len);
|
|
SS7Label lbl(label,sls,0);
|
|
SS7MSU answer(msu.getSIO(),lbl,0,len+2);
|
|
unsigned char* d = answer.getData(lbl.length()+1,len+2);
|
|
if (!d)
|
|
return false;
|
|
*d++ = SS7MsgMTN::SLTA;
|
|
*d++ = len << 4;
|
|
while (len--)
|
|
*d++ = *t++;
|
|
return transmitMSU(answer,lbl,sls) >= 0;
|
|
}
|
|
return true;
|
|
case SS7MsgMTN::SLTA:
|
|
Debug(this,DebugNote,"Received SLTA with test pattern length %u",len);
|
|
return true;
|
|
}
|
|
|
|
String tmp;
|
|
tmp.hexify((void*)s,mlen,' ');
|
|
Debug(this,DebugMild,"Unhandled MTN type %s length %u: %s",
|
|
SS7MsgMTN::lookup((SS7MsgMTN::Type)s[0],"unknown"),mlen,tmp.c_str());
|
|
return false;
|
|
}
|
|
|
|
void SS7Maintenance::notify(SS7Layer3* network, int sls)
|
|
{
|
|
Debug(this,DebugStub,"Please implement SS7Maintenance::notify(%p,%d) [%p]",
|
|
network,sls,this);
|
|
}
|
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|