mirror of
				https://github.com/RangeNetworks/openbts.git
				synced 2025-11-04 05:43:14 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			250 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/** @file Messages for call independent Supplementary Service Control, GSM 04.80 2.2.  */
 | 
						|
 | 
						|
/*
 | 
						|
* Copyright 2008, 2009 Free Software Foundation, Inc.
 | 
						|
* Copyright 2011, 2014 Range Networks, Inc.
 | 
						|
 | 
						|
* This software is distributed under multiple licenses;
 | 
						|
* see the COPYING file in the main directory for licensing
 | 
						|
* information for this specific distribution.
 | 
						|
*
 | 
						|
* This use of this software may be subject to additional restrictions.
 | 
						|
* See the LEGAL file in the main directory for details.
 | 
						|
 | 
						|
    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.
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#include <iostream>
 | 
						|
#include "GSML3SSMessages.h"
 | 
						|
#include <L3SupServ.h>
 | 
						|
#include <Logger.h>
 | 
						|
 | 
						|
 | 
						|
using namespace std;
 | 
						|
namespace GSM {
 | 
						|
 | 
						|
void L3SupServVersionIndicator::_define_vtable() {}	// Force the class vtable into this module.
 | 
						|
void L3SupServFacilityIE::_define_vtable() {}	// Force the class vtable into this module.
 | 
						|
 | 
						|
ostream& operator<<(ostream& os, const L3SupServVersionIndicator& ie)
 | 
						|
{
 | 
						|
	ie.text(os);
 | 
						|
	return os;
 | 
						|
}
 | 
						|
 | 
						|
ostream& operator<<(ostream& os, const L3SupServFacilityIE& ie)
 | 
						|
{
 | 
						|
	ie.text(os);
 | 
						|
	return os;
 | 
						|
}
 | 
						|
 | 
						|
ostream& operator<<(ostream& os, const L3SupServMessage& msg)
 | 
						|
{
 | 
						|
	msg.text(os);
 | 
						|
	return os;
 | 
						|
}
 | 
						|
 | 
						|
ostream& operator<<(ostream& os, const L3SupServMessage* msg)
 | 
						|
{
 | 
						|
	if (msg == NULL) os << "(null SS message)";
 | 
						|
	else msg->text(os);
 | 
						|
	return os;
 | 
						|
}
 | 
						|
 | 
						|
ostream& operator<<(ostream& os, L3SupServMessage::MessageType val)
 | 
						|
{
 | 
						|
	switch (val) {
 | 
						|
		case L3SupServMessage::ReleaseComplete: 
 | 
						|
			os << "ReleaseComplete"; break;
 | 
						|
		case L3SupServMessage::Facility:
 | 
						|
			os << "Facility"; break;
 | 
						|
		case L3SupServMessage::Register:
 | 
						|
			os << "Register"; break;
 | 
						|
		default: os << hex << "0x" << (int)val << dec;
 | 
						|
	}
 | 
						|
	return os;
 | 
						|
}
 | 
						|
 | 
						|
void L3OneByteProtocolElement::parseV(const L3Frame&src, size_t&rp, size_t expectedLength)
 | 
						|
{
 | 
						|
	if (expectedLength != 1) { LOG(ERR) << "Unexpected length="<<expectedLength <<" in one byte protocol element"; }	// Not much of a message.
 | 
						|
	if (expectedLength) { parseV(src,rp); }
 | 
						|
}
 | 
						|
 | 
						|
#if 0
 | 
						|
// Warning: If the expectedLenght is 0 then parseLV does not call us, so mExtant would be false,
 | 
						|
// but it does not matter anywhere because the Facility mComponentSize is inited to 0 and everything works out.
 | 
						|
void L3SupServFacilityIE::parseV(const L3Frame&src, size_t&rp, size_t expectedLength)
 | 
						|
{
 | 
						|
	assert(expectedLength < 256);
 | 
						|
	mExtant = true;
 | 
						|
	mComponentSize = expectedLength;		// 0 is allowed.
 | 
						|
	for (unsigned i = 0; i < expectedLength; i++) {
 | 
						|
		mComponents[i] = src.readField(rp,8);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServFacilityIE::writeV(L3Frame&dest, size_t&wp) const
 | 
						|
{
 | 
						|
	for (unsigned i = 0; i < mComponentSize; i++) {
 | 
						|
		dest.writeField(wp,mComponents[i],8);
 | 
						|
	}
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
void L3SupServFacilityIE::text(ostream& os) const
 | 
						|
{
 | 
						|
	char rawdata[2*255+1+1];		// Add 1 extra for luck.
 | 
						|
	unsigned len = lengthV();
 | 
						|
	const unsigned char *components = peData();
 | 
						|
	for (unsigned i = 0; i < len; i++) {
 | 
						|
		sprintf(&rawdata[2*i],"%02x",components[i]);
 | 
						|
	}
 | 
						|
	string ussd = Control::ssMap2Ussd(components,len);
 | 
						|
	os <<"SupServFacilityIE(size=" <<len <<" components:" <<LOGVAR(rawdata) <<LOGVAR(ussd)<<")";
 | 
						|
}
 | 
						|
 | 
						|
L3SupServMessage * L3SupServFactory(L3SupServMessage::MessageType MTI)
 | 
						|
{
 | 
						|
	LOG(DEBUG) << "Factory MTI"<< (int)MTI;
 | 
						|
	switch (MTI) {
 | 
						|
		case L3SupServMessage::Facility: return new L3SupServFacilityMessage();
 | 
						|
		case L3SupServMessage::Register: return new L3SupServRegisterMessage();
 | 
						|
		case L3SupServMessage::ReleaseComplete: return new L3SupServReleaseCompleteMessage();
 | 
						|
		default: {
 | 
						|
			//LOG(NOTICE) << "no L3 NonCallSS factory support for message "<< MTI;
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
L3SupServMessage * parseL3SupServ(const L3Frame& source)
 | 
						|
{
 | 
						|
	// mask out bit #7 (1011 1111) so use 0xbf
 | 
						|
	L3SupServMessage::MessageType MTI = (L3SupServMessage::MessageType)(0xbf & source.MTI());
 | 
						|
	LOG(DEBUG) << "MTI= "<< (int)MTI;
 | 
						|
	L3SupServMessage *retVal = L3SupServFactory(MTI);
 | 
						|
	if (retVal==NULL) return NULL;
 | 
						|
	retVal->setTI(source.TI());
 | 
						|
	retVal->parse(source);
 | 
						|
	LOG(DEBUG) << "parse L3 SS Message" << *retVal;
 | 
						|
	return retVal;
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServMessage::write(L3Frame& dest) const
 | 
						|
{
 | 
						|
	// We override L3Message::write for the transaction identifier.
 | 
						|
	size_t l3len = bitsNeeded();
 | 
						|
	if (dest.size()!=l3len) dest.resize(l3len);
 | 
						|
	size_t wp = 0;
 | 
						|
	dest.writeField(wp,mTI,4);
 | 
						|
	dest.writeField(wp,PD(),4);
 | 
						|
	dest.writeField(wp,MTI(),8);
 | 
						|
	writeBody(dest,wp);
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServMessage::text(ostream& os) const
 | 
						|
{
 | 
						|
	os << " MTI = " <<(MessageType) MTI();
 | 
						|
	os << " TI = " << mTI;
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServFacilityMessage::writeBody( L3Frame &dest, size_t &wp ) const
 | 
						|
{
 | 
						|
	mFacility.writeLV(dest,wp);
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServFacilityMessage::parseBody( const L3Frame &src, size_t &rp )
 | 
						|
{
 | 
						|
	mFacility.parseLV(src,rp);
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServFacilityMessage::text(ostream& os) const
 | 
						|
{
 | 
						|
	os <<"L3SSFacility(";
 | 
						|
		L3SupServMessage::text(os);
 | 
						|
		os << " facility=(" << mFacility << ")";	// Dump the facility IE from inside the layer3 facility message.
 | 
						|
	os << ")";
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServRegisterMessage::writeBody( L3Frame &dest, size_t &wp ) const
 | 
						|
{
 | 
						|
	mFacility.writeTLV(0x1c,dest,wp);		// Facility IE is mandatory, but it is permitted to be empty.
 | 
						|
	// The network to MS direction does not have a version indicator.
 | 
						|
	devassert(haveVersionIndicator() == false);
 | 
						|
	// However, we are going to write the message anyway in case of bugs
 | 
						|
	// where messages are converted to L3Frame and back.
 | 
						|
	if (haveVersionIndicator()) {
 | 
						|
		mVersionIndicator.writeTLV(0x7f,dest,wp);
 | 
						|
		//dest.writeField(wp,0x7F,8);		// The SS Version indicator IEI.
 | 
						|
		//dest.writeField(wp,1,8);		// Extreme dopeyness - it is a one byte field with a length specified.
 | 
						|
		//dest.writeField(wp,mVersionIndicator.mValue,8);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServRegisterMessage::parseBody( const L3Frame &src, size_t &rp )
 | 
						|
{
 | 
						|
	bool haveFacility = mFacility.parseTLV(0x1c,src,rp);
 | 
						|
	if (! haveFacility) {
 | 
						|
		LOG(ERR) << "Register message missing Facility IE";
 | 
						|
		// The L3SupServFacilityIE is inited with a content size of 0, so we need no further action.
 | 
						|
	}
 | 
						|
	mVersionIndicator.parseTLV(0x7f,src,rp);
 | 
						|
	//mHaveVersionIndicator = parseHasT(0x7f,src,rp);
 | 
						|
	//if (mHaveVersionIndicator) {
 | 
						|
	//	rp += 16;
 | 
						|
	//	mVersionIndicator = source.readField(rp,8);
 | 
						|
	//}
 | 
						|
}
 | 
						|
 | 
						|
size_t L3SupServRegisterMessage::l2BodyLength() const 
 | 
						|
{	
 | 
						|
	size_t sum=0;
 | 
						|
	sum += mFacility.lengthTLV();
 | 
						|
	if (haveVersionIndicator()) sum += 3;
 | 
						|
	return sum;
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServRegisterMessage::text(ostream& os) const
 | 
						|
{
 | 
						|
	os <<"L3SSRegister(";
 | 
						|
		L3SupServMessage::text(os);
 | 
						|
		os << " facility=(" << mFacility << ")";
 | 
						|
		if (haveVersionIndicator()) os << " version=" << mVersionIndicator.mValue;
 | 
						|
	os <<")";
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServReleaseCompleteMessage::writeBody( L3Frame &dest, size_t &wp ) const
 | 
						|
{
 | 
						|
	if (haveFacility()) mFacility.writeTLV(0x1c,dest,wp);
 | 
						|
	if (mHaveCause) mCause.writeTLV(0x08,dest,wp);
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServReleaseCompleteMessage::parseBody( const L3Frame &src, size_t &rp )
 | 
						|
{
 | 
						|
	mHaveCause = mCause.parseTLV(0x08,src,rp);
 | 
						|
	mFacility.parseTLV(0x1c,src,rp);
 | 
						|
}
 | 
						|
 | 
						|
size_t L3SupServReleaseCompleteMessage::l2BodyLength() const 
 | 
						|
{	
 | 
						|
	size_t sum=0;
 | 
						|
	if (mHaveCause) sum += mCause.lengthTLV();
 | 
						|
	if (haveFacility()) sum += mFacility.lengthTLV();
 | 
						|
	return sum;
 | 
						|
}
 | 
						|
 | 
						|
void L3SupServReleaseCompleteMessage::text(ostream& os) const
 | 
						|
{
 | 
						|
	L3SupServMessage::text(os);
 | 
						|
	if(haveFacility()) os << " facility=(" << mFacility << ")";
 | 
						|
	if(mHaveCause) os << " cause = " << mCause;
 | 
						|
}
 | 
						|
 | 
						|
};
 |