mirror of
https://github.com/RangeNetworks/openbts.git
synced 2025-10-23 07:42:01 +00:00
441 lines
12 KiB
C++
441 lines
12 KiB
C++
/**@file Elements for Call Control, GSM 04.08 10.5.4. */
|
|
/*
|
|
* Copyright 2008, 2009, 2014 Free Software Foundation, Inc.
|
|
* Copyright 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef GSML3CCELEMENTS_H
|
|
#define GSML3CCELEMENTS_H
|
|
|
|
#include "GSML3Message.h"
|
|
#include <iostream>
|
|
#include <CodecSet.h>
|
|
#include <Logger.h>
|
|
|
|
namespace GSM {
|
|
|
|
/** Bearer Capability, GSM 04.08 10.5.4.5 */
|
|
class L3BearerCapability : public L3ProtocolElement {
|
|
|
|
// Obsolete comment:
|
|
// The spec for this is really intimidating.
|
|
// But we're just going to assume circuit-switched speech
|
|
// with a full rate codec, since every phone supports that.
|
|
// So we can just ignore this hideously complex element.
|
|
|
|
// (pat) There may be multiple BearerCapability IEs for speech and non-speech.
|
|
// We save only the speech one; the speech version of this IE includes only Octet3
|
|
// and zero or more octet3a, one for each codec supported.
|
|
uint8_t mOctet3, mOctet3a[10];
|
|
unsigned mNumOctet3a; // Number of elements in mOctet3a.
|
|
|
|
public:
|
|
Bool_z mPresent;
|
|
|
|
L3BearerCapability() {
|
|
mOctet3 = 0x0f; // We hard code this octet for circuit switched speech.
|
|
mNumOctet3a = 1;
|
|
mOctet3a[0] = 0x80; // We hard code for full rate speech v1, the GSM 06.10 codec.
|
|
}
|
|
|
|
size_t lengthV() const { return 2; }
|
|
void writeV( L3Frame& dest, size_t &wp ) const;
|
|
void parseV( const L3Frame& src, size_t &rp, size_t expectedLength );
|
|
void parseV(const L3Frame&, size_t&) { assert(0); }
|
|
void text(std::ostream&) const;
|
|
|
|
// accessors
|
|
// Note: As defined in 26.103 and 48.008
|
|
// Meaning of these bits is hard to find: It is in 48.008 3.2.2.11:
|
|
// GSM speech full rate version 1: GSM FR
|
|
// GSM speech full rate version 2: GSM EFR
|
|
// GSM speech full rate version 3: FR AMR
|
|
// GSM speech full rate version 4: OFR AMR-WB
|
|
// GSM speech full rate version 5: FR AMR-WB
|
|
// GSM speech half rate version 1: GSM HR
|
|
// GSM speech half rate version 2: not defined
|
|
// GSM speech half rate version 3: HR AMR
|
|
// GSM speech half rate version 4: OHR AMR-WB
|
|
// GSM speech half rate version 6: OHR AMR
|
|
//unsigned getSpeechVersion() { return mOctet3 & 0xf; }
|
|
// Return the CodecType for the speech version in octet n;
|
|
Control::CodecType getCodecType(unsigned n) const;
|
|
Control::CodecType getCodecSet() const;
|
|
unsigned getHalfRateSupport() { return mOctet3 & 0x40; } // Bit 7 is true if half-rate supported.
|
|
};
|
|
|
|
// (pat) Added 10-22-2012.
|
|
// 3GPP 24.008 10.5.4.32 and 3GPP 26.103
|
|
// I added this IE before I read the fine print. This is only used for UMTS, and the BearerCapability
|
|
// is used for GSM radio networks, so we dont really need this, since any UMTS phone supports AMR_FR,
|
|
// which is all we care. But here it is.
|
|
class L3SupportedCodecList : public L3ProtocolElement
|
|
{
|
|
Control::CodecSet mGsmCodecs, mUmtsCodecs;
|
|
enum { // SysID defined in 26.103 6.1
|
|
SysIdGSM = 0,
|
|
SysIdUMTS = 4
|
|
};
|
|
public:
|
|
Bool_z mPresent; // Was the IE present?
|
|
Bool_z mGsmPresent, mUmtsPresent; // Were these sub-parts of the IE present?
|
|
L3SupportedCodecList() {}
|
|
Control::CodecSet getCodecSet() const; // Return codec set for gsm in OpenBTS or umts in OpenNodeB
|
|
// Each sub-section is 4 bytes.
|
|
size_t lengthV() const { return (mGsmPresent?4:0) + (mUmtsPresent?4:0); } // length excluding IEI and initial length byte.
|
|
void writeV( L3Frame& dest, size_t &wp ) const;
|
|
void parseV( const L3Frame& src, size_t &rp, size_t expectedLength );
|
|
void parseV(const L3Frame&, size_t&) { assert(0); } // This IE must always include an initial length byte.
|
|
void text(std::ostream&) const;
|
|
};
|
|
|
|
|
|
|
|
class L3CCCapabilities
|
|
{
|
|
public:
|
|
/// Bearer Capability IE
|
|
// (pat) BearerCapability is sent by GSM phone
|
|
//Bool_z mHaveBearerCapability;
|
|
L3BearerCapability mBearerCapability;
|
|
|
|
// (pat) SupportedCodecList is sent by UMTS phone
|
|
//Bool_z mHaveSupportedCodecs;
|
|
L3SupportedCodecList mSupportedCodecs; // (pat) added 10-22-2012
|
|
|
|
// Return the CodecSet for the radio access capability we are in.
|
|
Control::CodecSet getCodecSet() const;
|
|
};
|
|
|
|
/** A general class for BCD numbers as they normally appear in L3. */
|
|
class L3BCDDigits {
|
|
|
|
private:
|
|
|
|
static const unsigned maxDigits = 20;
|
|
char mDigits[maxDigits+1]; ///< ITU-T E.164 limits address to 15 digits
|
|
|
|
public:
|
|
|
|
L3BCDDigits() { mDigits[0]='\0'; }
|
|
|
|
// (pat) The -1 below and +1 above are mutually redundant.
|
|
L3BCDDigits(const char* wDigits) { strncpy(mDigits,wDigits,sizeof(mDigits)-1); mDigits[sizeof(mDigits)-1]='\0'; }
|
|
|
|
L3BCDDigits(const L3BCDDigits &other) {
|
|
memcpy(mDigits,other.mDigits,sizeof(mDigits));
|
|
}
|
|
|
|
void parse(const L3Frame& src, size_t &rp, size_t numOctets, bool international = false);
|
|
void write(L3Frame& dest, size_t &wp) const;
|
|
|
|
/** Return number of octets needed to encode the digits. */
|
|
size_t lengthV() const;
|
|
|
|
unsigned size() const { return strlen(mDigits); }
|
|
const char* digits() const { return mDigits; }
|
|
};
|
|
|
|
|
|
std::ostream& operator<<(std::ostream&, const L3BCDDigits&);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Calling Party BCD Number, GSM 04.08 10.5.4.9 */
|
|
// (pat) 24.018 10.5.4.9 quote: "This IE is not used in the MS to network direction."
|
|
class L3CallingPartyBCDNumber : public L3ProtocolElement {
|
|
|
|
private:
|
|
|
|
TypeOfNumber mType;
|
|
NumberingPlan mPlan;
|
|
|
|
L3BCDDigits mDigits;
|
|
|
|
/**@name Octet 3a */
|
|
//@{
|
|
Bool_z mHaveOctet3a;
|
|
int mPresentationIndicator; // uninited, but not used unless mHaveOctet3a
|
|
int mScreeningIndicator; // uninited, but not used unless mHaveOctet3a
|
|
//@}
|
|
|
|
|
|
public:
|
|
|
|
L3CallingPartyBCDNumber()
|
|
:mType(UnknownTypeOfNumber), mPlan(UnknownPlan),
|
|
mHaveOctet3a(false)
|
|
{ }
|
|
|
|
L3CallingPartyBCDNumber( const char * wDigits )
|
|
:mPlan(E164Plan), mDigits(wDigits),
|
|
mHaveOctet3a(false)
|
|
{
|
|
mType = (wDigits[0] == '+') ? GSM::InternationalNumber : GSM::NationalNumber;
|
|
//LOG(DEBUG) << "L3CallingPartyBCDNumber ctor type=" << mType << " Digits " << wDigits; (pat) what was "ctor"?
|
|
LOG(DEBUG) << "L3CallingPartyBCDNumber create type=" << mType << " Digits " << wDigits;
|
|
}
|
|
|
|
L3CallingPartyBCDNumber(const L3CallingPartyBCDNumber &other)
|
|
:mType(other.mType),mPlan(other.mPlan),mDigits(other.mDigits),
|
|
mHaveOctet3a(other.mHaveOctet3a),
|
|
mPresentationIndicator(other.mPresentationIndicator),
|
|
mScreeningIndicator(other.mScreeningIndicator)
|
|
{}
|
|
|
|
|
|
NumberingPlan plan() const { return mPlan; }
|
|
TypeOfNumber type() const { return mType; }
|
|
const char* digits() const { return mDigits.digits(); }
|
|
|
|
size_t lengthV() const;
|
|
void writeV( L3Frame& dest, size_t &wp ) const;
|
|
void parseV( const L3Frame& src, size_t &rp, size_t expectedLength);
|
|
void parseV(const L3Frame&, size_t&) { assert(0); }
|
|
void text(std::ostream&) const;
|
|
};
|
|
|
|
|
|
/** Called Party BCD Number, GSM 04.08 10.5.4.7 */
|
|
class L3CalledPartyBCDNumber : public L3ProtocolElement {
|
|
|
|
|
|
private:
|
|
|
|
TypeOfNumber mType;
|
|
NumberingPlan mPlan;
|
|
L3BCDDigits mDigits;
|
|
|
|
public:
|
|
|
|
L3CalledPartyBCDNumber()
|
|
:mType(UnknownTypeOfNumber),
|
|
mPlan(UnknownPlan)
|
|
{ }
|
|
|
|
L3CalledPartyBCDNumber(const char * wDigits)
|
|
:mPlan(E164Plan), mDigits(wDigits)
|
|
{
|
|
mType = (wDigits[0] == '+') ? GSM::InternationalNumber : GSM::NationalNumber;
|
|
LOG(DEBUG) << "L3CallingPartyBCDNumber ctor type=" << mType << " Digits " << wDigits;
|
|
}
|
|
|
|
// (pat) This auto-conversion from CallingParty to CalledParty was used in the SMS code,
|
|
// however, it was creating a disaster during unintended auto-conversions of L3Messages,
|
|
// which are unintentionally sprinkled throughout the code base due to incomplete constructors.
|
|
// The fix would be to add 'explicit' keywords everywhere.
|
|
explicit L3CalledPartyBCDNumber(const L3CallingPartyBCDNumber& other)
|
|
:mType(other.type()),mPlan(other.plan()),mDigits(other.digits())
|
|
{ }
|
|
|
|
// (pat) We must have this constructor as a choice also.
|
|
L3CalledPartyBCDNumber(const L3CalledPartyBCDNumber& other)
|
|
:mType(other.mType),mPlan(other.mPlan),mDigits(other.mDigits)
|
|
{ }
|
|
|
|
|
|
NumberingPlan plan() const { return mPlan; }
|
|
TypeOfNumber type() const { return mType; }
|
|
const char* digits() const { return mDigits.digits(); }
|
|
|
|
size_t lengthV() const ;
|
|
void writeV( L3Frame& dest, size_t &wp ) const;
|
|
void parseV( const L3Frame& src, size_t &rp, size_t expectedLength );
|
|
void parseV(const L3Frame&, size_t&) { assert(0); }
|
|
void text(std::ostream&) const;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
Cause, GSM 04.08 10.5.4.11
|
|
Very poorly names, it is the Call Control cause.
|
|
Read the spec closely: we only have to support coding standard 3 (GSM),
|
|
and that format doesn't carry the "recommendation" field.
|
|
*/
|
|
|
|
class L3CauseElement : public L3ProtocolElement {
|
|
public:
|
|
typedef L3Cause::Location Location;
|
|
typedef L3Cause::CCCause Cause;
|
|
|
|
private:
|
|
|
|
// FIXME -- This should include any supplied diagnostics.
|
|
// See ticket GSM 04.08 10.5.4.11 and ticket #1139.
|
|
|
|
Location mLocation;
|
|
Cause mCause; // 7 bits of cause, consisting of 3 bit "class" and 4 bit "value".
|
|
|
|
public:
|
|
|
|
L3CauseElement(Cause wCause=L3Cause::Normal_Call_Clearing, Location wLocation=L3Cause::Private_Serving_Local)
|
|
:L3ProtocolElement(),
|
|
mLocation(wLocation),mCause(wCause)
|
|
{ }
|
|
|
|
Location location() const { return mLocation; }
|
|
Cause cause() const { return mCause; }
|
|
|
|
// We don't support diagnostics, so length=2.
|
|
size_t lengthV() const { return 2; }
|
|
|
|
void writeV( L3Frame& dest, size_t &wp) const;
|
|
void parseV( const L3Frame& src, size_t &rp , size_t expectedLength );
|
|
void parseV(const L3Frame&, size_t&) { assert(0); }
|
|
void text(std::ostream&) const;
|
|
};
|
|
|
|
|
|
/** Call State, GSM 04.08 10.5.4.6. */
|
|
class L3CallState : public L3ProtocolElement {
|
|
|
|
private:
|
|
|
|
unsigned mCallState;
|
|
|
|
public:
|
|
|
|
/** The default call state is the "Null" state. */
|
|
L3CallState( unsigned wCallState=0 )
|
|
:L3ProtocolElement(),
|
|
mCallState(wCallState)
|
|
{ }
|
|
|
|
unsigned callState() const { return mCallState; }
|
|
|
|
size_t lengthV()const { return 1;}
|
|
void writeV( L3Frame& dest, size_t &wp) const;
|
|
void parseV( const L3Frame& src, size_t &rp );
|
|
void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
|
|
void text(std::ostream&) const;
|
|
|
|
};
|
|
|
|
/** GSM 04.08 10.5.4.21 */
|
|
class L3ProgressIndicator : public L3ProtocolElement {
|
|
|
|
public:
|
|
|
|
enum Location {
|
|
User=0,
|
|
PrivateServingLocal=1,
|
|
PublicServingLocal=2,
|
|
PublicServingRemote=4,
|
|
PrivateServingRemote=5,
|
|
BeyondInternetworking=10
|
|
};
|
|
|
|
// pat 2-2014: GSM 4.08 5.5.1: The ProgressIndicator is used to start in-band tones and announcements
|
|
// if the value is 1-3 or 6-20.
|
|
enum Progress {
|
|
Unspecified=0,
|
|
NotISDN=1,
|
|
DestinationNotISDN=2,
|
|
OriginationNotISDN=3,
|
|
ReturnedToISDN=4,
|
|
InBandAvailable=8,
|
|
EndToEndISDN=0x20,
|
|
Queuing=0x40
|
|
};
|
|
|
|
private:
|
|
|
|
Location mLocation;
|
|
Progress mProgress;
|
|
|
|
public:
|
|
|
|
/** Default values are unspecified progress in the BTS. */
|
|
L3ProgressIndicator(Progress wProgress=Unspecified, Location wLocation=PrivateServingLocal)
|
|
:L3ProtocolElement(),
|
|
mLocation(wLocation),mProgress(wProgress)
|
|
{}
|
|
|
|
Location location() const { return mLocation; }
|
|
Progress progress() const { return mProgress; }
|
|
|
|
size_t lengthV() const { return 2; }
|
|
void writeV(L3Frame& dest, size_t &wp ) const;
|
|
void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
|
|
void parseV(const L3Frame&, size_t&) { assert(0); }
|
|
void text(std::ostream&) const;
|
|
};
|
|
|
|
|
|
/** GSM 04.08 10.5.4.17 */
|
|
class L3KeypadFacility : public L3ProtocolElement {
|
|
|
|
private:
|
|
|
|
char mIA5;
|
|
|
|
public:
|
|
|
|
L3KeypadFacility(char wIA5=0)
|
|
:mIA5(wIA5)
|
|
{}
|
|
|
|
char IA5() const { return mIA5; }
|
|
|
|
size_t lengthV() const { return 1; }
|
|
void writeV(L3Frame&, size_t&) const;
|
|
void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
|
|
void parseV(const L3Frame& src, size_t& rp);
|
|
void text(std::ostream&) const;
|
|
};
|
|
|
|
|
|
/** GSM 04.08 10.5.4.23 */
|
|
// (pat) 2-2014: Added to try to work around bug that ZTE phone does not play ring-back tone during Alerting.
|
|
class L3Signal : public L3ProtocolElement {
|
|
char mSignalValue;
|
|
public:
|
|
enum SignalValues {
|
|
SignalDialToneOn = 0,
|
|
SignalRingBackToneOn = 1,
|
|
SignalInterceptToneOn = 2,
|
|
SignalNetworkCongestionToneOn = 3,
|
|
SignalBusyToneOn = 4,
|
|
SignalConfirmToneOn = 5,
|
|
SignalAnswerToneOn = 6,
|
|
SignalCallWaitingToneOn = 7,
|
|
SignalTonesOff = 0x3f,
|
|
SignalAlertingOff = 0x4f
|
|
};
|
|
L3Signal(SignalValues tone = SignalRingBackToneOn) : mSignalValue(tone) {}
|
|
|
|
size_t lengthV() const { return 1; }
|
|
void writeV(L3Frame&, size_t&) const;
|
|
void parseV(const L3Frame&, size_t&, size_t) { assert(0); }
|
|
void parseV(const L3Frame& src, size_t& rp);
|
|
void text(std::ostream&) const;
|
|
};
|
|
|
|
} // GSM
|
|
|
|
#endif
|
|
// vim: ts=4 sw=4
|