merged in commercial openbts

This commit is contained in:
Michael Iedema
2014-03-25 00:06:30 +01:00
parent 9ab1b0d9d5
commit c13f8bde8f
194 changed files with 33161 additions and 12847 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2008, 2009, 2010, 2014 Free Software Foundation, Inc.
*
This program is distributed in the hope that it will be useful,
@@ -54,6 +54,7 @@ CPMessage * SMS::CPFactory(CPMessage::MessageType val)
// (pat) This parses an incoming SMS message from the MS, called from
CPMessage * SMS::parseSMS( const GSM::L3Frame& frame )
{
CPMessage::MessageType MTI = (CPMessage::MessageType)(frame.MTI());
@@ -62,7 +63,13 @@ CPMessage * SMS::parseSMS( const GSM::L3Frame& frame )
CPMessage * retVal = CPFactory(MTI);
if( retVal==NULL ) return NULL;
retVal->TI(frame.TI());
retVal->parse(frame);
// Documentation courtesy pat:
// The L3Message::CPMessage is a base class for CPData, CPAck, CPError, one of which is created by the CPFactory above.
// The below calls L3Message::parse which calls the parseBody from the derived class.
// For CPAck and CPError, parseBody is null (or worse, assert out - a former bug.)
// For CPData messages: calls CPData::parseBody which then calls L3ProtocolElement::parseLV which calls:
// CPUserData::parseV, which just copies the data into CPUserData::mRPDU; which is an L3Frame::RLFrame
retVal->parse(frame);
LOG(DEBUG) << *retVal;
return retVal;
}
@@ -72,7 +79,7 @@ RPData *SMS::hex2rpdata(const char *hexstring)
{
RPData *rp_data = NULL;
BitVector RPDUbits(strlen(hexstring)*4);
BitVector2 RPDUbits(strlen(hexstring)*4);
if (!RPDUbits.unhex(hexstring)) {
return false;
}
@@ -102,11 +109,12 @@ RPData *SMS::hex2rpdata(const char *hexstring)
return rp_data;
}
TLMessage *SMS::parseTPDU(const TLFrame& TPDU)
TLMessage *SMS::parseTPDU(const TLFrame& TPDU, bool directionUplink)
{
LOG(DEBUG) << "SMS: parseTPDU MTI=" << TPDU.MTI();
// Handle just the uplink cases.
switch ((TLMessage::MessageType)TPDU.MTI()) {
if (directionUplink) {
// Handle just the uplink cases.
switch ((TLMessage::MessageType)TPDU.MTI()) {
case TLMessage::DELIVER_REPORT:
case TLMessage::STATUS_REPORT:
// FIXME -- Not implemented yet.
@@ -120,13 +128,25 @@ TLMessage *SMS::parseTPDU(const TLFrame& TPDU)
}
default:
return NULL;
}
} else {
switch ((TLMessage::MessageType)TPDU.MTI()) {
// 10-2013: Pat added the DELIVER which is the downlink message so we can parse it for reporting purposes.
case TLMessage::DELIVER: {
TLDeliver *deliver = new TLDeliver(TPDU);
return deliver;
}
default:
LOG(WARNING) << "parsing unsupported TPDU type: " << (TLMessage::MessageType)TPDU.MTI();
return NULL;
}
}
}
void CPMessage::text(ostream& os) const
{
os << (CPMessage::MessageType)MTI();
os <<" TI=" << mTI;
os <<LOGHEX2("TI",mTI);
}
@@ -166,10 +186,18 @@ void CPError::writeBody( L3Frame& dest, size_t &wp ) const
}
// called from SMS::parseSMS.
void CPUserData::parseV(const L3Frame& src, size_t &rp, size_t expectedLength)
{
unsigned numBits = expectedLength*8;
// WARNING: segmentCopyTo does not modify the size of the target so we must do it.
mRPDU.resize(numBits);
int actualLength = (int) src.size() - rp;
if (actualLength < (int)numBits) {
// The length field (third byte) in the L3Frame was bogus, less than the remaining length of the frame.
LOG(ERR)<<"Invalid SMS frame:"<<LOGVAR(expectedLength*8) <<" (from L3 header)"<<LOGVAR(actualLength);
L3_READ_ERROR;
}
src.segmentCopyTo(mRPDU,rp,numBits);
rp += numBits;
}
@@ -413,7 +441,7 @@ void TLValidityPeriod::parse(const TLFrame& src, size_t& rp)
// Absolute format, borrowed from GSM 04.08 MM
// GSM 03.40 9.2.3.12.2
L3TimeZoneAndTime decoder;
decoder.parseV((TLFrame)(BitVector)src,rp);
decoder.parseV((TLFrame)(BitVector2)src,rp);
mExpiration = decoder.time();
return;
}
@@ -477,7 +505,7 @@ void TLUserData::encode7bit(const char *text)
// 2. Write TP-UD
// This tail() works because UD is always the last field in the PDU.
BitVector chars = mRawData.tail(wp);
BitVector2 chars = mRawData.tail(wp);
for (unsigned i=0; i<mLength; i++) {
char gsm = encodeGSMChar(text[i]);
mRawData.writeFieldReversed(wp,gsm,7);
@@ -579,7 +607,7 @@ void TLUserData::parse(const TLFrame& src, size_t& rp)
mLength = src.readField(rp,8);
#if 1
// This tail() works because UD is always the last field in the PDU.
mRawData.clone(src.tail(rp));
mRawData.clone(src.alias().tail(rp)); // TODO: Could use cloneSegment
// Should we do this here?
mRawData.LSB8MSB();
#else
@@ -597,7 +625,7 @@ void TLUserData::parse(const TLFrame& src, size_t& rp)
LOG(NOTICE) << "badly formatted TL-UD";
SMS_READ_ERROR;
}
BitVector chars(src.tail(rp));
BitVector2 chars(src.tail(rp));
chars.LSB8MSB();
size_t crp=0;
for (unsigned i=0; i<numChar; i++) {
@@ -629,7 +657,7 @@ void TLUserData::write(TLFrame& dest, size_t& wp) const
// Then write TP-User-Data
// This tail() works because UD is always the last field in the PDU.
BitVector ud_dest = dest.tail(wp);
BitVector2 ud_dest = dest.tail(wp);
mRawData.copyTo(ud_dest);
ud_dest.LSB8MSB();
#else
@@ -639,7 +667,7 @@ void TLUserData::write(TLFrame& dest, size_t& wp) const
unsigned numChar = strlen(mData);
dest.writeField(wp,numChar,8);
// This tail() works because UD is always the last field in the PDU.
BitVector chars = dest.tail(wp);
BitVector2 chars = dest.tail(wp);
chars.zero();
for (unsigned i=0; i<numChar; i++) {
char gsm = encodeGSMChar(mData[i]);
@@ -660,8 +688,12 @@ void TLUserData::text(ostream& os) const
}
// (pat 10-2013) This is just wrong. The contents of the first byte depend
// on the message type, so there is no separate "body". This routine should not
// skip the first byte, it should let the invidual parsers crack out the TLMessage header bits.
void TLMessage::parse(const TLFrame& src)
{
// FIXME -- Check MTI for consistency.
size_t rp=8;
return parseBody(src,rp);
@@ -683,6 +715,31 @@ size_t TLSubmit::l2BodyLength() const
return 1 + mDA.length() + 1 + 1 + mVP.length() + mUD.length();
}
// GSM 3.40 9.2.2.1
TLDeliver::TLDeliver(const TLFrame& fm)
{
size_t rp = 8;
parseBody(fm,rp);
}
void TLDeliver::parseBody(const TLFrame &src, size_t &rp)
{
// Note that offset is reversed, i'=7-i.
// Ignore MTI, we already know it is DELIVER.
// Note that these header fields come from src ignoring rp.
parseMMS(src);
parseRP(src);
parseUDHI(src);
parseSRI(src);
// Now the 'body'
assert(rp == 8);
mOA.parse(src,rp); // originating address.
mPID = src.readField(rp,8); // protocol id
mUD.DCS(src.readField(rp,8)); // data coding scheme, stored in the TLUserData.
mSCTS.parse(src,rp); // time stamp
mUD.parse(src,rp); // user data.
}
void TLSubmit::parseBody(const TLFrame& src, size_t& rp)
{
@@ -729,27 +786,34 @@ size_t TLDeliver::l2BodyLength() const
}
// (pat) See 3GPP 3.40 9.2.2
void TLDeliver::writeBody(TLFrame& dest, size_t& wp) const
{
writeMMS(dest);
writeRP(dest);
writeUDHI(dest, mUD.UDHI());
writeSRI(dest);
mOA.write(dest,wp);
dest.writeField(wp,mPID,8);
dest.writeField(wp,mUD.DCS(),8);
mSCTS.write(dest,wp);
writeUnused(dest);
mUD.write(dest,wp);
writeMMS(dest); // more messages to send bit.
writeRP(dest); // reply path bit.
writeUDHI(dest, mUD.UDHI()); // User-data-header-indicator bit
writeSRI(dest); // status-report-indication bit
mOA.write(dest,wp); // originating address
dest.writeField(wp,mPID,8); // protocol id
dest.writeField(wp,mUD.DCS(),8); // Data-coding-scheme
mSCTS.write(dest,wp); // service-centre-time-stamp
writeUnused(dest); // user-data-length. (pat) Why empty?
mUD.write(dest,wp); // user data.
}
void TLDeliver::text(ostream& os) const
{
TLMessage::text(os);
os << " OA=(" << mOA << ")";
os << " SCTS=(" << mSCTS << ")";
os << " UD=(" << mUD << ")";
os << " OriginatingAddress=(" << mOA << ")";
os << " SCTimeStamp=(" << mSCTS << ")";
os << " DataCodingScheme="<<mUD.DCS();
os << " UserData=(" << mUD << ")";
}
void TLTimestamp::text(std::ostream&os) const
{
mTime.text(os);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2008, 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.
*
@@ -141,8 +141,9 @@ class TLTimestamp : public TLElement {
void time(const Timeval& wTime) { mTime.time(wTime); }
size_t length() const { return mTime.lengthV(); }
void write(TLFrame& dest, size_t& wp) const { mTime.writeV((GSM::L3Frame&)(BitVector&)dest, wp); }
void parse(const TLFrame& src, size_t& rp) { mTime.parseV((GSM::L3Frame&)(BitVector&)src, rp); }
void write(TLFrame& dest, size_t& wp) const { mTime.writeV((GSM::L3Frame&)(BitVector2&)dest, wp); }
void parse(const TLFrame& src, size_t& rp) { mTime.parseV((GSM::L3Frame&)(BitVector2&)src, rp); }
void text(std::ostream&os) const;
};
@@ -156,7 +157,7 @@ class TLUserData : public TLElement {
bool mUDHI; ///< header indicator
unsigned mLength; ///< TP-User-Data-Length, see GSM 03.40 Fig. 9.2.3.24(a),
///< GSM 03.40 Fig. 9.2.3.24(b) and GSM 03.40 9.2.3.16.
BitVector mRawData; ///< raw packed data
BitVector2 mRawData; ///< raw packed data
public:
@@ -170,7 +171,7 @@ class TLUserData : public TLElement {
}
/** Initialize from a raw encoded data. */
TLUserData(unsigned wDCS, const BitVector wRawData, unsigned wLength,
TLUserData(unsigned wDCS, const BitVector2 wRawData, unsigned wLength,
bool wUDHI=false)
:TLElement(),
mDCS(wDCS),
@@ -288,7 +289,7 @@ class TLMessage {
virtual void writeBody( TLFrame& frame, size_t &rp) const =0;
virtual void text(std::ostream& os) const
{ os << MTI(); }
{ os << "MTI="<<MTI(); }
// Accessors
bool MMS() const { return mMMS; }
@@ -312,7 +313,7 @@ class TLMessage {
void writeSRQ(TLFrame& fm) const { fm[2]=mSRQ; }
void parseSRQ(const TLFrame& fm) { mSRQ=fm[2]; }
void writeUDHI(TLFrame& fm, bool udhi) const { fm[1]=udhi; }
bool parseUDHI(const TLFrame& fm) { return fm[1]; }
bool parseUDHI(const TLFrame& fm) { return mUDHI = fm[1]; }
void writeRP(TLFrame& fm) const { fm[0]=mRP; }
void parseRP(const TLFrame& fm) { mRP=fm[0]; }
void writeUnused(TLFrame& fm) const { fm.fill(0,3,2); } ///< Fill unused bits with 0s
@@ -375,7 +376,7 @@ class TLDeliver : public TLMessage {
private:
TLAddress mOA; ///< origination address, GSM 03.40 9.3.2.7
TLAddress mOA; ///< origination address, GSM 03.40 9.2.3.7
unsigned mPID; ///< TL-PID, GSM 03.40 9.2.3.9
// DCS is taken from mUD.
TLTimestamp mSCTS; ///< service center timestamp, GSM 03.40 9.2.3.11
@@ -392,12 +393,15 @@ class TLDeliver : public TLMessage {
:TLMessage(),
mUD(wUD)
{}
// (pat 10-2013) This form is to re-parse a downlink message for inspection.
TLDeliver(const TLFrame& input);
int MTI() const { return DELIVER; }
size_t l2BodyLength() const;
void writeBody( TLFrame& frame, size_t& wp ) const;
void parseBody(const TLFrame&, size_t&) { assert(0); }
void parseBody(const TLFrame&, size_t&);
virtual void text( std::ostream& os ) const;
};
@@ -437,10 +441,10 @@ class RPUserData : public GSM::L3ProtocolElement {
private:
// The BitVector is a placeholder for a higher-layer object.
// The BitVector2 is a placeholder for a higher-layer object.
public:
TLFrame mTPDU;
public:
RPUserData()
:L3ProtocolElement(),
@@ -469,7 +473,7 @@ class RPUserData : public GSM::L3ProtocolElement {
}
void writeV(GSM::L3Frame& dest, size_t &wp) const;
void parseV(const GSM::L3Frame& src, size_t &rp) { assert(0); }
void parseV(const GSM::L3Frame& /*src*/, size_t &/*rp*/) { assert(0); }
void parseV(const GSM::L3Frame& src, size_t &rp, size_t expectedLength);
void text(std::ostream& os) const { mTPDU.hex(os); }
@@ -576,9 +580,9 @@ class RPData : public RPMessage {
RPAddress mOriginator; ///< originating SMSC
RPAddress mDestination; ///< destination SMSC
public:
RPUserData mUserData; ///< payload
public:
RPData():RPMessage() {}
@@ -627,8 +631,8 @@ class RPAck : public RPMessage {
int MTI() const { return Ack; }
void writeBody(RLFrame& frame, size_t &wp) const {}
void parseBody( const RLFrame& frame, size_t &rp) {}
void writeBody(RLFrame& /*frame*/, size_t &/*wp*/) const {}
void parseBody( const RLFrame& /*frame*/, size_t &/*rp*/) {}
size_t l2BodyLength() const { return 0; }
};
@@ -693,7 +697,7 @@ class CPCause : public GSM::L3ProtocolElement {
void writeV(GSM::L3Frame& dest, size_t &wp) const
{ dest.writeField(wp,mValue,8); }
void parseV(const GSM::L3Frame& src, size_t &rp, size_t) { assert(0); }
void parseV(const GSM::L3Frame& /*src*/, size_t &/*rp*/, size_t) { assert(0); }
void parseV(const GSM::L3Frame& src, size_t &rp)
{ mValue = src.readField(rp,8); }
@@ -728,8 +732,8 @@ class CPUserData : public GSM::L3ProtocolElement {
size_t lengthV() const { return mRPDU.size()/8; }
void writeV(GSM::L3Frame& dest, size_t &wp) const;
void parseV(const GSM::L3Frame& src, size_t &rp, size_t expectedLength);
void parseV(const GSM::L3Frame& src, size_t &rp) { assert(0); }
void text(std::ostream& os) const { mRPDU.hex(os); }
void parseV(const GSM::L3Frame& /*src*/, size_t &/*rp*/) { assert(0); }
void text(std::ostream& os) const { mRPDU.text(os); } // called for operator<<(...,CPUserData) by L3ProtocolElement.
};
//@} // CP Elements
@@ -807,7 +811,7 @@ RPData *hex2rpdata(const char *hexstring);
@param TPDU The TPDU.
@return Pointer to parsed TLMessage or NULL on error.
*/
TLMessage *parseTPDU(const TLFrame& TPDU);
TLMessage *parseTPDU(const TLFrame& TPDU, bool directionUplink = false);
/** A factory method for SMS L3 (CM) messages. */
CPMessage * CPFactory( CPMessage::MessageType MTI );
@@ -826,8 +830,8 @@ class CPAck : public CPMessage
int MTI() const { return ACK; }
size_t l2BodyLength() const { return 0; }
void parseBody(const GSM::L3Frame& dest, size_t &rp) {};
void writeBody(GSM::L3Frame& dest, size_t &wp) const {};
void parseBody(const GSM::L3Frame& /*dest*/, size_t &/*rp*/) {};
void writeBody(GSM::L3Frame& /*dest*/, size_t &/*wp*/) const {};
void text(std::ostream& os) const { CPMessage::text(os); }
};
@@ -856,7 +860,9 @@ class CPError : public CPMessage
int MTI() const { return ERROR; }
size_t l2BodyLength() const { return mCause.lengthV(); }
void writeBody(GSM::L3Frame& dest, size_t &wp) const;
void parseBody(const GSM::L3Frame&, size_t&) { assert(0); }
// pat 5-14-2013: This was an assert, but I believe this can happen because parseSMS does not triage out this type
// of message, so changed to devassert.
void parseBody(const GSM::L3Frame&, size_t&) { devassert(0); }
};

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2008, 2014 Free Software Foundation, Inc.
*
This program is distributed in the hope that it will be useful,
@@ -16,6 +16,7 @@
#include <BitVector.h>
#include "SMSTransfer.h"
#include "SMSMessages.h"
using namespace std;
using namespace SMS;
@@ -23,6 +24,7 @@ using namespace SMS;
#if UNUSED_PRIMITIVE
ostream& SMS::operator<<(ostream& os, SMSPrimitive prim)
{
switch(prim) {
@@ -39,24 +41,100 @@ ostream& SMS::operator<<(ostream& os, SMSPrimitive prim)
case MNSMS_EST_IND: os<<"MNSMS-EST-IND "; break;
case MNSMS_ERROR_IND: os<<"MNSMS-ERROR-IND "; break;
case MNSMS_REL_REQ: os<<"MNSMS-REL-REQ "; break;
case UNDEFINED_PRIMITIVE: os<<"undefined "; break;
case SMS_UNDEFINED_PRIMITIVE: os<<"undefined "; break;
}
return os;
}
#endif
void RLFrame::text(std::ostream& os) const
{
#if UNUSED_PRIMITIVE
os<<"primitive="<<primitive();
#endif
if (size() >= 16) {
os <<LOGVAR2("MTI",MTI());
switch (MTI()) {
case 0: case 1: os << " (RP-DATA)";
try {
// GSM 4.11 7.3.1
size_t rp = 16;
RPData rpdata;
rpdata.parseBody(*this,rp);
rpdata.text(os);
//os << "RP-Originator=("; rpdata.mOriginator.text(os); os << ")";
//os << "RP-Destination=("; rpdata.mDestination.text(os); os << ")";
// The rpdata.mUserData.mTPDU is a TLFrame, which we must parse into one of the messages in GSM 3.40 9.2
TLMessage *tlmsg = parseTPDU(rpdata.mUserData.mTPDU);
if (tlmsg) {
os << " TLMessage=(";
tlmsg->text(os);
os << ")";
delete tlmsg;
}
#if 0
int RPOriginatorAddressLength = 8*readField(rp,8);
if (rp + RPOriginatorAddressLength > size()) {
os << " out-of-bounds"<<LOGVAR(RPOriginatorAddressLength) << " remaining:"<<size();
break;
}
const BitVector2 RPOriginatorAddress ( segment(rp,RPOriginatorAddressLength));
os <<LOGVAR(rp)<<" bitvector:"<<RPOriginatorAddress;
os << " orig:"<<inspect()<<" "<<peekField(rp,8) << " copy:"<<RPOriginatorAddress.inspect()<<" "<<RPOriginatorAddress.peekField(0,8);
os << " RP-OriginatorAddress=("; RPOriginatorAddress.hex(os); os <<")";
rp += RPOriginatorAddressLength;
int RPDestinationAddressLength = 8*readField(rp,8); // In network->MS direction this is zero.
if (rp + RPDestinationAddressLength > size()) {
os << " out-of-bounds"<<LOGVAR(RPDestinationAddressLength) << " remaining:"<<size();
break;
}
const BitVector RPDestinationAddress = segment(rp,RPDestinationAddressLength);
os << " RP-DestinationAddress=("; RPDestinationAddress.hex(os); os <<")";
rp += RPDestinationAddressLength;
int RPUserDataLength = 8*readField(rp,8);
if (rp + RPUserDataLength > size()) {
os << " out-of-bounds"<<LOGVAR(RPUserDataLength) << " remaining:"<<size();
break;
}
const BitVector2 RPUserData = segment(rp,RPUserDataLength);
rp += RPUserDataLength;
TLFrame tpdu(RPUserData); // GSM 4.11 8.2.5.3
os << " TPDU=("; os << tpdu; os << ")";
#endif
} catch (...) {
os << " (error parsing rp-data) ";
}
break;
case 2: case 3: os << " (RP-ACK)"; break;
case 4: case 5:
os << " (RP-ERROR)";
os << " cause="<<RPErrorCause();
break;
case 6: case 7: os << " (RP-SMMA)"; break;
}
os <<LOGVAR2("reference",reference());
}
os<<" data=(";
hex(os);
os<< ")";
}
ostream& SMS::operator<<(ostream& os, const RLFrame& msg)
{
os<<"primitive="<<msg.primitive();
os<<" data=(";
msg.hex(os);
os<< ")";
msg.text(os);
return os;
}
ostream& SMS::operator<<(ostream& os, const TLFrame& msg)
{
#if UNUSED_PRIMITIVE
os<<"primitive="<<msg.primitive();
#endif
if (msg.size() >= 8) { os <<LOGVAR2("MTI",msg.MTI()); }
os<<" data=(";
msg.hex(os);
os<< ")";

View File

@@ -25,6 +25,9 @@ namespace SMS {
#if UNUSED_PRIMITIVE
// (pat 10-2013) This wonderful enum is referenced in RLFrame and TLFrame but not actually used anywhere
// so I am eliding it pending proof that it has some functional requirement.
enum SMSPrimitive {
// Relay layer primitives for network
@@ -44,34 +47,46 @@ enum SMSPrimitive {
MNSMS_EST_IND=9, // MO RPDU
MNSMS_ERROR_IND=10, // Cause
MNSMS_REL_REQ=11, // Cause
UNDEFINED_PRIMITIVE=-1
SMS_UNDEFINED_PRIMITIVE=-1
};
std::ostream& operator<<(std::ostream& os, SMSPrimitive);
#endif
// GSM 4.11 8.2
class RLFrame : public GSM::L3Frame
{
#if UNUSED_PRIMITIVE
SMSPrimitive mPrimitive;
void RLFrameInit() { mPrimitive = SMS_UNDEFINED_PRIMITIVE; }
#endif
public:
unsigned MTI() const { return peekField(5,3); }
unsigned reference() const { return peekField(8,8); }
// GSM 4.11 7.3.4 for RP-ERROR fields 8.2.5.4 for RP-Cause.
unsigned RPErrorCause() const { return size() >= 32 ? peekField(25,7) : 0; } // Only valid for RP-Error message.
RLFrame(SMSPrimitive wPrimitive=UNDEFINED_PRIMITIVE, size_t len=0)
#if ORIGINAL
RLFrame(SMSPrimitive wPrimitive=SMS_UNDEFINED_PRIMITIVE, size_t len=0)
:L3Frame(GSM::DATA,len), mPrimitive(wPrimitive)
{ }
RLFrame(const BitVector& source, SMSPrimitive wPrimitive=UNDEFINED_PRIMITIVE)
RLFrame(const BitVector2& source, SMSPrimitive wPrimitive=SMS_UNDEFINED_PRIMITIVE)
:L3Frame(source), mPrimitive(wPrimitive)
{ }
#endif
RLFrame(size_t bitsNeeded=0) :L3Frame(GSM::DATA,bitsNeeded) { /*RLFrameInit();*/ }
RLFrame(const BitVector2& source) :L3Frame(GSM::SAPIUndefined,source) { /*RLFrameInit();*/ }
void text(std::ostream& os) const;
#if UNUSED_PRIMITIVE
SMSPrimitive primitive() const { return mPrimitive; }
#endif
};
std::ostream& operator<<(std::ostream& os, const RLFrame& );
@@ -79,22 +94,29 @@ std::ostream& operator<<(std::ostream& os, const RLFrame& );
class TLFrame : public GSM::L3Frame
{
#if UNUSED_PRIMITIVE
SMSPrimitive mPrimitive;
void TLFrameInit() { mPrimitive = SMS_UNDEFINED_PRIMITIVE; }
#endif
public:
unsigned MTI() const { return peekField(6,2); }
TLFrame(SMSPrimitive wPrimitive=UNDEFINED_PRIMITIVE, size_t len=0)
#if ORIGINAL
TLFrame(SMSPrimitive wPrimitive=SMS_UNDEFINED_PRIMITIVE, size_t len=0)
:L3Frame(GSM::DATA,len), mPrimitive(wPrimitive)
{ }
TLFrame(const BitVector& source, SMSPrimitive wPrimitive=UNDEFINED_PRIMITIVE)
TLFrame(const BitVector2& source, SMSPrimitive wPrimitive=SMS_UNDEFINED_PRIMITIVE)
:L3Frame(source), mPrimitive(wPrimitive)
{ }
#endif
TLFrame(size_t bitsNeeded=0) :L3Frame(GSM::DATA,bitsNeeded) { /*TLFrameInit();*/ }
TLFrame(const BitVector2& source) :L3Frame(GSM::SAPIUndefined,source) { /*TLFrameInit();*/ }
#if UNUSED_PRIMITIVE
SMSPrimitive primitive() const { return mPrimitive; }
#endif
};