mirror of
https://github.com/RangeNetworks/openbts.git
synced 2025-11-02 04:43:16 +00:00
merged in commercial openbts
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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<< ")";
|
||||
|
||||
@@ -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
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user