mirror of
https://github.com/RangeNetworks/openbts.git
synced 2025-11-02 12:53:15 +00:00
Fixed all places where + was not being sent. Plus can't be sent as a digit it has to be encoded as an international type. Fixed error where # is displayed in reply address for +. SMS reply not working with plus in from address. Fixed all places in smqueue that crash on purpose when bad data is found. Fixed several other crashes related to handling missing tags. Added support for receiving addresses with and without +. Whether a + is received or not depends on what the sender enters. 3gpp mode is working. Fixed error where smqueue gets into an infinite loop when restarted with bad messages in the queue.
473 lines
13 KiB
C++
473 lines
13 KiB
C++
/**@file Elements for Call Control, GSM 04.08 10.5.4. */
|
|
/*
|
|
* Copyright 2008, 2009, 2014 Free Software Foundation, Inc.
|
|
*
|
|
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
|
|
*
|
|
* 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 <ControlTransfer.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;
|
|
}
|
|
|
|
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 L3Cause : public L3ProtocolElement {
|
|
|
|
public:
|
|
|
|
enum Location {
|
|
User=0,
|
|
PrivateServingLocal=1,
|
|
PublicServingLocal=2,
|
|
Transit=3,
|
|
PublicServingRemote=4,
|
|
PrivateServingRemote=5,
|
|
International=7,
|
|
BeyondInternetworking=10
|
|
};
|
|
|
|
enum Cause {
|
|
UnassignedNumber = 1, // or unallocated number
|
|
NoRouteToDestination = 3,
|
|
ChannelUnacceptable = 6,
|
|
OperatorDeterminedBarring = 8,
|
|
NormalCallClearing = 16,
|
|
UserBusy = 17,
|
|
NoUserResponding = 18,
|
|
UserAlertingNoAnswer = 19,
|
|
CallRejected = 21,
|
|
NumberChanged = 22,
|
|
Preemption = 25,
|
|
NonSelectedUserClearing = 26,
|
|
DestinationOutOfOrder = 27,
|
|
InvalidNumberFormat = 28, // invalid or incomplete number
|
|
FacilityRejected = 29,
|
|
ResponseToSTATUSENQUIRY = 30,
|
|
NormalUnspecified = 31,
|
|
NoChannelAvailable = 34,
|
|
NetworkOutOfOrder = 38,
|
|
TemporaryFailure = 41,
|
|
SwitchingEquipmentCongestion = 42,
|
|
AccessInformationDiscarded = 43,
|
|
RequestedChannelNotAvailable = 44,
|
|
ResourcesUnavailable = 47,
|
|
QualityOfServiceUnavailable = 49,
|
|
RequestedFacilityNotSubscribed = 50,
|
|
IncomingCallsBarredWithinCUG = 55,
|
|
BearerCapabilityNotAuthorized = 57,
|
|
BearerCapabilityNotPresentlyAvailable = 58,
|
|
ServiceOrOptionNotAvailable = 63,
|
|
BearerServiceNotImplemented = 65,
|
|
ACMGEMax = 68, // ACM greater or equal to ACM max. Whatever that is.
|
|
RequestedFacilityNotImplemented = 69,
|
|
OnlyRestrictedDigitalInformationBearerCapabilityIsAvailable = 70, // If you ever use, go ahead and abbreviate it.
|
|
ServiceOrOptionNotImplemented = 79,
|
|
InvalidTransactionIdentifiervalue = 81,
|
|
UserNotMemberOfCUG = 87,
|
|
IncompatibleDestination = 88,
|
|
InvalidTransitNetworkSelection = 91,
|
|
SemanticallyIncorrectMessage = 95,
|
|
InvalidMandatoryInformation = 96,
|
|
MessageTypeNotImplemented = 97,
|
|
MessagetypeNotCompatibleWithProtocolState = 98,
|
|
IENotImplemented = 99, // Information Element non-existent or not implemented.
|
|
ConditionalIEError = 100,
|
|
MessageNotCompatibleWithProtocolState = 101,
|
|
RecoveryOnTimerExpiry = 102,
|
|
ProtocolErrorUnspecified = 111,
|
|
InterworkingUnspecified = 127,
|
|
};
|
|
|
|
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:
|
|
|
|
L3Cause(Cause wCause=NormalCallClearing, Location wLocation=PrivateServingLocal)
|
|
:L3ProtocolElement(),
|
|
mLocation(wLocation),mCause(wCause)
|
|
{ }
|
|
|
|
Location location() const { return mLocation; }
|
|
unsigned 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;
|
|
};
|
|
typedef L3Cause::Cause CCCause;
|
|
|
|
|
|
/** 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
|
|
};
|
|
|
|
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
|
|
|
|
#endif
|
|
// vim: ts=4 sw=4
|