OpenBTS-UMTS/GSM/GSML3CCMessages.h

646 lines
13 KiB
C++

/**@file Messages for Call Control, GSM 04.08 9.3. */
/*
* OpenBTS provides an open source alternative to legacy telco protocols and
* traditionally complex, proprietary hardware systems.
*
* Copyright 2008, 2009 Free Software Foundation, Inc.
* Copyright 2011, 2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero General
* Public License version 3. See the COPYING and NOTICE files in the main
* directory for licensing information.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
*/
#ifndef GSML3CCMESSAGES_H
#define GSML3CCMESSAGES_H
#include "GSMCommon.h"
#include "GSML3Message.h"
#include "GSML3CommonElements.h"
#include "GSML3CCElements.h"
namespace GSM {
/**
This a virtual class for L3 messages in the Call Control protocol.
These messages are defined in GSM 04.08 9.3.
GSM call control is based on and nearly identical to ISDN call control.
ISDN call control is defined in ITU-T Q.931.
*/
class L3CCMessage : public L3Message {
private:
unsigned mTI; ///< short transaction ID, GSM 04.07 11.2.3.1.3; upper bit is originator flag
// Uppder bit is 0 for originating side, see GSM 04.07 11.2.3.1.3.
public:
/** GSM 04.08, Table 10.3, bit 6 is "don't care" */
enum MessageType {
/**@name call establishment */
//@{
Alerting=0x01,
CallConfirmed=0x08,
CallProceeding=0x02,
Connect=0x07,
Setup=0x05,
EmergencySetup=0x0e,
ConnectAcknowledge=0x0f,
Progress=0x03,
//@}
/**@name call clearing */
//@{
Disconnect=0x25,
Release=0x2d,
ReleaseComplete=0x2a,
//@}
/**@name DTMF */
//@{
StartDTMF=0x35,
StopDTMF=0x31,
StopDTMFAcknowledge=0x32,
StartDTMFAcknowledge=0x36,
StartDTMFReject=0x37,
//@}
/**@name In-call services */
//@{
Hold=0x18,
HoldReject=0x1a,
//@}
/**@name error reporting */
//@{
CCStatus= 0x3d
//@}
};
L3CCMessage(unsigned wTI)
:L3Message(),mTI(wTI)
{}
size_t fullBodyLength() const { return l2BodyLength(); }
/** Override the write method to include transaction identifiers in header. */
void write(L3Frame& dest) const;
L3PD PD() const { return L3CallControlPD; }
unsigned TI() const { return mTI; }
void TI(unsigned wTI) { mTI = wTI; }
void text(std::ostream&) const;
};
std::ostream& operator<<(std::ostream& os, L3CCMessage::MessageType MTI);
/**
Parse a complete L3 call control message into its object type.
@param source The L3 bits.
@return A pointer to a new message or NULL on failure.
*/
L3CCMessage* parseL3CC(const L3Frame& source);
/**
A Factory function to return a L3CCMessage of the specified MTI.
Returns NULL if the MTI is not supported.
*/
L3CCMessage* L3CCFactory(L3CCMessage::MessageType MTI);
/** GSM 04.08 9.3.19 */
class L3Release : public L3CCMessage {
private:
// We're ignoring "facility" and "user-user" for now.
bool mHaveCause;
L3Cause mCause;
public:
L3Release(unsigned wTI=7)
:L3CCMessage(wTI),
mHaveCause(false)
{}
L3Release(unsigned wTI, const L3Cause& wCause)
:L3CCMessage(wTI),
mHaveCause(true),mCause(wCause)
{}
int MTI() const { return Release; }
void writeBody( L3Frame &dest, size_t &wp ) const;
void parseBody( const L3Frame &src, size_t &rp );
size_t l2BodyLength() const;
void text(std::ostream&) const;
};
class L3CCStatus : public L3CCMessage
{
private:
L3Cause mCause;
L3CallState mCallState;
public:
L3CCStatus(unsigned wTI=7)
:L3CCMessage(wTI)
{}
L3CCStatus(unsigned wTI, const L3Cause &wCause, const L3CallState &wCallState)
:L3CCMessage(wTI),
mCause(wCause),
mCallState(wCallState)
{}
int MTI() const { return CCStatus; }
void writeBody( L3Frame &dest, size_t &wp ) const;
void parseBody( const L3Frame &src, size_t &rp );
size_t l2BodyLength() const { return 4; }
void text(std::ostream&) const;
};
/** GSM 04.08 9.3.19 */
class L3ReleaseComplete : public L3CCMessage {
private:
// We're ignoring "facility" and "user-user" for now.
bool mHaveCause;
L3Cause mCause;
public:
L3ReleaseComplete(unsigned wTI=7)
:L3CCMessage(wTI),
mHaveCause(false)
{}
L3ReleaseComplete(unsigned wTI, const L3Cause& wCause)
:L3CCMessage(wTI),
mHaveCause(true),mCause(wCause)
{}
int MTI() const { return ReleaseComplete; }
void writeBody( L3Frame &dest, size_t &wp ) const;
void parseBody( const L3Frame &src, size_t &rp );
size_t l2BodyLength() const;
void text(std::ostream&) const;
};
/**
GSM 04.08 9.3.23
This message can have different forms for uplink and downlink
but the TLV format is flexiable enough to allow us to use one class for both.
*/
class L3Setup : public L3CCMessage
{
// We fill in IEs one at a time as we need them.
/// Bearer Capability IE
bool mHaveBearerCapability;
L3BearerCapability mBearerCapability;
/// Calling Party BCD Number (0x5C O TLV 3-19 ).
bool mHaveCallingPartyBCDNumber;
L3CallingPartyBCDNumber mCallingPartyBCDNumber;
/// Called Party BCD Number (0x5E O TLV 3-19).
bool mHaveCalledPartyBCDNumber;
L3CalledPartyBCDNumber mCalledPartyBCDNumber;
public:
L3Setup(unsigned wTI=7)
:L3CCMessage(wTI),
mHaveBearerCapability(false),
mHaveCallingPartyBCDNumber(false),
mHaveCalledPartyBCDNumber(false)
{ }
L3Setup(unsigned wTI, const L3CalledPartyBCDNumber& wCalledPartyBCDNumber)
:L3CCMessage(wTI),
mHaveBearerCapability(false),
mHaveCallingPartyBCDNumber(false),
mHaveCalledPartyBCDNumber(true),mCalledPartyBCDNumber(wCalledPartyBCDNumber)
{ }
L3Setup(unsigned wTI, const L3CallingPartyBCDNumber& wCallingPartyBCDNumber)
:L3CCMessage(wTI),
mHaveBearerCapability(false),
mHaveCallingPartyBCDNumber(true),mCallingPartyBCDNumber(wCallingPartyBCDNumber),
mHaveCalledPartyBCDNumber(false)
{ }
/** Accessors */
//@{
bool haveCalledPartyBCDNumber() const { return mHaveCalledPartyBCDNumber; }
const L3CalledPartyBCDNumber& calledPartyBCDNumber() const
{ assert(mHaveCalledPartyBCDNumber); return mCalledPartyBCDNumber; }
//@}
int MTI() const { return Setup; }
void writeBody( L3Frame &dest, size_t &wp ) const;
void parseBody( const L3Frame &src, size_t &rp );
size_t l2BodyLength() const;
void text(std::ostream&) const;
};
/**
GSM 04.08 9.3.8
*/
class L3EmergencySetup : public L3CCMessage
{
// We fill in IEs one at a time as we need them.
public:
L3EmergencySetup(unsigned wTI=7)
:L3CCMessage(wTI)
{ }
int MTI() const { return EmergencySetup; }
void parseBody( const L3Frame &src, size_t &rp ) {}
size_t l2BodyLength() const { return 0; }
};
/** GSM 04.08 9.3.3 */
class L3CallProceeding : public L3CCMessage {
private:
// We'fill in IEs one at a time as we need them.
bool mHaveBearerCapability;
L3BearerCapability mBearerCapability;
bool mHaveProgress;
L3ProgressIndicator mProgress;
public:
L3CallProceeding(unsigned wTI=7)
:L3CCMessage(wTI),
mHaveBearerCapability(false),
mHaveProgress(false)
{}
int MTI() const { return CallProceeding; }
void writeBody( L3Frame & dest, size_t &wp ) const;
void parseBody( const L3Frame &src, size_t &wp );
size_t l2BodyLength() const;
void text(std::ostream&) const;
};
/**
GSM 04.08 9.3.1.
Even though uplink and downlink forms have different optional fields,
we can use a single message for both sides.
*/
class L3Alerting : public L3CCMessage
{
private:
bool mHaveProgress;
L3ProgressIndicator mProgress; ///< Progress appears in uplink only.
public:
L3Alerting(unsigned wTI=7)
:L3CCMessage(wTI),
mHaveProgress(false)
{}
L3Alerting(unsigned wTI,const L3ProgressIndicator& wProgress)
:L3CCMessage(wTI),
mHaveProgress(true),mProgress(wProgress)
{}
int MTI() const { return Alerting; }
void writeBody(L3Frame &dest, size_t &wp) const;
void parseBody(const L3Frame& src, size_t &rp);
size_t l2BodyLength() const;
void text(std::ostream&) const;
};
/** GSM 04.08 9.3.5 */
class L3Connect : public L3CCMessage
{
private:
bool mHaveProgress;
L3ProgressIndicator mProgress; ///< Progress appears in uplink only.
public:
L3Connect(unsigned wTI=7)
:L3CCMessage(wTI),
mHaveProgress(false)
{}
L3Connect(unsigned wTI, const L3ProgressIndicator& wProgress)
:L3CCMessage(wTI),
mHaveProgress(true),mProgress(wProgress)
{}
int MTI() const { return Connect; }
void writeBody( L3Frame &dest, size_t &wp ) const;
void parseBody(const L3Frame &src, size_t &wp);
size_t l2BodyLength() const;
void text(std::ostream&) const;
};
/** GSM 04.08 9.3.6 */
class L3ConnectAcknowledge : public L3CCMessage
{
public:
L3ConnectAcknowledge(unsigned wTI=7)
:L3CCMessage(wTI)
{}
int MTI() const { return ConnectAcknowledge; }
void writeBody( L3Frame &dest, size_t &wp ) const {}
void parseBody( const L3Frame &src, size_t &rp ) {}
size_t l2BodyLength() const { return 0; }
};
/** GSM 04.08 9.3.7 */
class L3Disconnect : public L3CCMessage {
private:
L3Cause mCause;
public:
/** Initialize with default cause of 0x10 "normal call clearing". */
L3Disconnect(unsigned wTI=7, const L3Cause& wCause = L3Cause(0x10))
:L3CCMessage(wTI),
mCause(wCause)
{}
int MTI() const { return Disconnect; }
void writeBody( L3Frame &dest, size_t &wp ) const;
void parseBody( const L3Frame &src, size_t &rp );
size_t l2BodyLength() const { return mCause.lengthLV(); }
void text(std::ostream&) const;
};
/** GSM 04.08 9.3.2 */
class L3CallConfirmed : public L3CCMessage {
private:
bool mHaveCause;
L3Cause mCause;
public:
L3CallConfirmed(unsigned wTI=7)
:L3CCMessage(wTI),
mHaveCause(false)
{}
int MTI() const { return CallConfirmed; }
void parseBody(const L3Frame &src, size_t &rp);
size_t l2BodyLength() const;
void text(std::ostream& os) const;
};
/** GSM 04.08 9.3.24 */
class L3StartDTMF : public L3CCMessage {
private:
L3KeypadFacility mKey;
public:
L3StartDTMF(unsigned wTI=7)
:L3CCMessage(wTI)
{}
const L3KeypadFacility& key() const { return mKey; }
int MTI() const { return StartDTMF; }
void parseBody(const L3Frame &src, size_t &rp) { mKey.parseTV(0x2c,src,rp); }
size_t l2BodyLength() const { return mKey.lengthTV(); }
void text(std::ostream& os) const;
};
/** GSM 04.08 9.3.25 */
class L3StartDTMFAcknowledge : public L3CCMessage {
private:
L3KeypadFacility mKey;
public:
L3StartDTMFAcknowledge(unsigned wTI, const L3KeypadFacility& wKey)
:L3CCMessage(wTI),
mKey(wKey)
{}
int MTI() const { return StartDTMFAcknowledge; }
void writeBody(L3Frame &dest, size_t &wp) const { mKey.writeTV(0x2C,dest,wp); }
size_t l2BodyLength() const { return mKey.lengthTV(); }
void text(std::ostream& os) const;
};
/** GSM 04.08 9.3.26 */
class L3StartDTMFReject : public L3CCMessage {
private:
L3Cause mCause;
public:
/** Reject with default cause 0x3f, "service or option not available". */
L3StartDTMFReject(unsigned wTI, const L3Cause& wCause)
:L3CCMessage(wTI),
mCause(wCause)
{}
int MTI() const { return StartDTMFReject; }
void writeBody(L3Frame &src, size_t &rp) const { mCause.writeLV(src,rp); }
size_t l2BodyLength() const { return mCause.lengthLV(); }
void text(std::ostream& os) const;
};
/** GSM 04.08 9.3.29 */
class L3StopDTMF : public L3CCMessage {
public:
L3StopDTMF(unsigned wTI=7)
:L3CCMessage(wTI)
{}
int MTI() const { return StopDTMF; }
void parseBody(const L3Frame &src, size_t &rp) { }
size_t l2BodyLength() const { return 0; };
};
/** GSM 04.08 9.3.30 */
class L3StopDTMFAcknowledge : public L3CCMessage {
public:
L3StopDTMFAcknowledge(unsigned wTI)
:L3CCMessage(wTI)
{}
int MTI() const { return StopDTMFAcknowledge; }
void writeBody(L3Frame&, size_t&) const { }
size_t l2BodyLength() const { return 0; }
};
/** GSM 04.08 9.3.17 */
class L3Progress : public L3CCMessage
{
L3ProgressIndicator mProgress;
public:
L3Progress(unsigned wTI, const L3ProgressIndicator& wProgress)
:L3CCMessage(wTI),
mProgress(wProgress)
{}
L3Progress(unsigned wTI)
:L3CCMessage(wTI)
{}
int MTI() const { return Progress; }
void writeBody( L3Frame &dest, size_t &wp ) const;
void parseBody(const L3Frame &src, size_t &wp);
size_t l2BodyLength() const;
void text(std::ostream&) const;
};
/** GSM 04.08 9.3.10 */
class L3Hold : public L3CCMessage
{
public:
L3Hold(unsigned wTI=7)
:L3CCMessage(wTI)
{}
int MTI() const { return Hold; }
void writeBody( L3Frame &dest, size_t &wp ) const {}
void parseBody( const L3Frame &src, size_t &rp ) {}
size_t l2BodyLength() const { return 0; }
};
/** GSM 04.08 9.3.12 */
class L3HoldReject : public L3CCMessage {
private:
L3Cause mCause;
public:
/** Reject with default cause 0x3f, "service or option not available". */
L3HoldReject(unsigned wTI, const L3Cause& wCause)
:L3CCMessage(wTI),
mCause(wCause)
{}
int MTI() const { return HoldReject; }
void writeBody(L3Frame &src, size_t &rp) const { mCause.writeLV(src,rp); }
size_t l2BodyLength() const { return mCause.lengthLV(); }
void text(std::ostream& os) const;
};
/** GSM 04.08 9.3.6 */
}; // GSM
#endif
// vim: ts=4 sw=4