laforge
/
openbts-osmo
Archived
1
0
Fork 0
This repository has been archived on 2022-03-30. You can view files and clone it, but cannot push or open issues or pull requests.
openbts-osmo/public-trunk/GSM/GSML3RRMessages.cpp

689 lines
18 KiB
C++

/**@file
@brief GSM Radio Resorce messages, from GSM 04.08 9.1.
*/
/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <typeinfo>
#include <iostream>
#include "GSML3RRMessages.h"
#include <Logger.h>
using namespace std;
using namespace GSM;
void L3Message::writeBody(L3Frame&,size_t&) const
{
LOG(ERROR) << "not implemented for " << MTI();
assert(0);
}
void L3Message::parseBody(const L3Frame&, size_t&)
{
LOG(ERROR) << "not implemented for " << MTI();
assert(0);
}
ostream& GSM::operator<<(ostream& os, L3RRMessage::MessageType val)
{
switch (val) {
case L3RRMessage::SystemInformationType1:
os << "System Information Type 1"; break;
case L3RRMessage::SystemInformationType2:
os << "System Information Type 2"; break;
case L3RRMessage::SystemInformationType2bis:
os << "System Information Type 2bis"; break;
case L3RRMessage::SystemInformationType2ter:
os << "System Information Type 2ter"; break;
case L3RRMessage::SystemInformationType3:
os << "System Information Type 3"; break;
case L3RRMessage::SystemInformationType4:
os << "System Information Type 4"; break;
case L3RRMessage::SystemInformationType5:
os << "System Information Type 5"; break;
case L3RRMessage::SystemInformationType5bis:
os << "System Information Type 5bis"; break;
case L3RRMessage::SystemInformationType5ter:
os << "System Information Type 5ter"; break;
case L3RRMessage::SystemInformationType6:
os << "System Information Type 6"; break;
case L3RRMessage::SystemInformationType7:
os << "System Information Type 7"; break;
case L3RRMessage::SystemInformationType8:
os << "System Information Type 8"; break;
case L3RRMessage::SystemInformationType9:
os << "System Information Type 9"; break;
case L3RRMessage::SystemInformationType13:
os << "System Information Type 13"; break;
case L3RRMessage::SystemInformationType16:
os << "System Information Type 16"; break;
case L3RRMessage::SystemInformationType17:
os << "System Information Type 17"; break;
case L3RRMessage::PagingResponse:
os << "Paging Response"; break;
case L3RRMessage::PagingRequestType1:
os << "Paging Request Type 1"; break;
case L3RRMessage::MeasurementReport:
os << "Measurement Report"; break;
case L3RRMessage::AssignmentComplete:
os << "Assignment Complete"; break;
case L3RRMessage::ImmediateAssignment:
os << "Immediate Assignment"; break;
case L3RRMessage::ImmediateAssignmentReject:
os << "Immediate Assignment Reject"; break;
case L3RRMessage::AssignmentCommand:
os << "Assignment Command"; break;
case L3RRMessage::AssignmentFailure:
os << "Assignment Failure"; break;
case L3RRMessage::ChannelRelease:
os << "Channel Release"; break;
case L3RRMessage::ChannelModeModify:
os << "Channel Mode Modify"; break;
case L3RRMessage::ChannelModeModifyAcknowledge:
os << "Channel Mode Modify Acknowledge"; break;
case L3RRMessage::GPRSSuspensionRequest:
os << "GPRS Suspension Request"; break;
case L3RRMessage::ClassmarkEnquiry:
os << "Classmark Enquiry"; break;
case L3RRMessage::ClassmarkChange:
os << "Classmark Change"; break;
case L3RRMessage::RRStatus:
os << "RR Status"; break;
case L3RRMessage::ApplicationInformation:
os << "Application Information"; break;
default: os << hex << "0x" << (int)val << dec;
}
return os;
}
void L3RRMessage::text(ostream& os) const
{
os << "RR " << (MessageType) MTI() << " ";
}
L3RRMessage* GSM::L3RRFactory(L3RRMessage::MessageType MTI)
{
switch (MTI) {
case L3RRMessage::ChannelRelease: return new L3ChannelRelease();
case L3RRMessage::AssignmentComplete: return new L3AssignmentComplete();
case L3RRMessage::AssignmentFailure: return new L3AssignmentFailure();
case L3RRMessage::RRStatus: return new L3RRStatus();
case L3RRMessage::PagingResponse: return new L3PagingResponse();
case L3RRMessage::ChannelModeModifyAcknowledge: return new L3ChannelModeModifyAcknowledge();
case L3RRMessage::ClassmarkChange: return new L3ClassmarkChange();
case L3RRMessage::ClassmarkEnquiry: return new L3ClassmarkEnquiry();
case L3RRMessage::MeasurementReport: return new L3MeasurementReport();
case L3RRMessage::ApplicationInformation: return new L3ApplicationInformation();
// Partial support just to get along with some phones.
case L3RRMessage::GPRSSuspensionRequest: return new L3GPRSSuspensionRequest();
default:
LOG(WARN) << "no L3 RR factory support for " << MTI;
return NULL;
}
}
L3RRMessage* GSM::parseL3RR(const L3Frame& source)
{
L3RRMessage::MessageType MTI = (L3RRMessage::MessageType)source.MTI();
LOG(DEBUG) << "parseL3RR MTI="<<MTI;
L3RRMessage *retVal = L3RRFactory(MTI);
if (retVal==NULL) return NULL;
retVal->parse(source);
return retVal;
}
/**
This is a local function to map the GSM::ChannelType enum
to one of the codes from GMS 04.08 10.5.2.8.
*/
unsigned channelNeededCode(ChannelType wType)
{
switch (wType) {
case AnyDCCHType: return 0;
case SDCCHType: return 1;
case TCHFType: return 2;
case AnyTCHType: return 3;
default: assert(0);
}
}
size_t L3PagingRequestType1::bodyLength() const
{
int sz = mMobileIDs.size();
assert(sz<=2);
size_t sum=1;
sum += mMobileIDs[0].lengthLV();
if (sz>1) sum += mMobileIDs[1].lengthTLV();
return sum;
}
void L3PagingRequestType1::writeBody(L3Frame& dest, size_t &wp) const
{
// See GSM 04.08 9.1.22.
// Page Mode Page Mode M V 1/2 10.5.2.26
// Channels Needed M V 1/2
// Mobile Identity 1 M LV 2-9 10.5.1.4
// 0x17 Mobile Identity 2 O TLV 3-10 10.5.1.4
int sz = mMobileIDs.size();
assert(sz<=2);
// Remember to reverse orders of 1/2-octet fields.
// Because GSM transmits LSB-first within each byte.
// channel needed codes
dest.writeField(wp,channelNeededCode(mChannelsNeeded[1]),2);
dest.writeField(wp,channelNeededCode(mChannelsNeeded[0]),2);
// "normal paging", GSM 04.08 Table 10.5.63
dest.writeField(wp,0x0,4);
// the actual mobile IDs
mMobileIDs[0].writeLV(dest,wp);
if (sz>1) mMobileIDs[1].writeTLV(0x17,dest,wp);
}
void L3PagingRequestType1::text(ostream& os) const
{
L3RRMessage::text(os);
os << " mobileIDs=(";
for (unsigned i=0; i<mMobileIDs.size(); i++) {
os << "(" << mMobileIDs[i] << "," << mChannelsNeeded[i] << "),";
}
os << ")";
}
size_t L3PagingResponse::bodyLength() const
{
return 1 + mClassmark.lengthLV() + mMobileID.lengthLV();
}
void L3PagingResponse::parseBody(const L3Frame& src, size_t &rp)
{
// THIS CODE IS CORRECT. DON'T CHANGE IT. -- DAB
rp += 8; // skip cipher key seq # and spare half octet
// TREAT THIS AS LV!!
mClassmark.parseLV(src,rp);
// We only care about the mobile ID.
mMobileID.parseLV(src,rp);
}
void L3PagingResponse::text(ostream& os) const
{
L3RRMessage::text(os);
os << "mobileID=(" << mMobileID << ")";
os << " classmark=(" << mClassmark << ")";
}
void L3SystemInformationType1::writeBody(L3Frame& dest, size_t &wp) const
{
/*
System Information Message Type 1, GSM 04.08 9.1.31
- Cell Channel Description 10.5.2.1b M V 16
- RACH Control Parameters 10.5.2.29 M V 3
*/
mCellChannelDescription.writeV(dest,wp);
mRACHControlParameters.writeV(dest,wp);
}
void L3SystemInformationType1::text(ostream& os) const
{
L3RRMessage::text(os);
os << "cellChannelDescription=(" << mCellChannelDescription << ")";
os << " RACHControlParameters=(" << mRACHControlParameters << ")";
}
void L3SystemInformationType2::writeBody(L3Frame& dest, size_t &wp) const
{
/*
System Information Type 2, GSM 04.08 9.1.32.
- BCCH Frequency List 10.5.2.22 M V 16
- NCC Permitted 10.5.2.27 M V 1
- RACH Control Parameter 10.5.2.29 M V 3
*/
mBCCHFrequencyList.writeV(dest,wp);
mNCCPermitted.writeV(dest,wp);
mRACHControlParameters.writeV(dest,wp);
}
void L3SystemInformationType2::text(ostream& os) const
{
L3RRMessage::text(os);
os << "BCCHFrequencyList=(" << mBCCHFrequencyList << ")";
os << " NCCPermitted=(" << mNCCPermitted << ")";
os << " RACHControlParameters=(" << mRACHControlParameters << ")";
}
void L3SystemInformationType3::writeBody(L3Frame& dest, size_t &wp) const
{
/*
System Information Type 3, GSM 04.08 9.1.35
- Cell Identity 10.5.1.1 M V 2
- Location Area Identification 10.5.1.3 M V 5
- Control Channel Description 10.5.2.11 M V 3
- Cell Options (BCCH) 10.5.2.3 M V 1
- Cell Selection Parameters 10.5.2.4 M V 2
- RACH Control Parameters 10.5.2.29 M V 3
*/
mCI.writeV(dest,wp);
mLAI.writeV(dest,wp);
mControlChannelDescription.writeV(dest,wp);
mCellOptions.writeV(dest,wp);
mCellSelectionParameters.writeV(dest,wp);
mRACHControlParameters.writeV(dest,wp);
}
void L3SystemInformationType3::text(ostream& os) const
{
L3RRMessage::text(os);
os << "LAI=(" << mLAI << ")";
os << " CI=" << mCI;
os << " controlChannelDescription=(" << mControlChannelDescription << ")";
os << " cellOptions=(" << mCellOptions << ")";
os << " cellSelectionParameters=(" << mCellSelectionParameters << ")";
os << " RACHControlParameters=(" << mRACHControlParameters << ")";
}
void L3SystemInformationType4::writeBody(L3Frame& dest, size_t &wp) const
{
/*
System Information Type 4, GSM 04.08 9.1.36
- Location Area Identification 10.5.1.3 M V 5
- Cell Selection Parameters 10.5.2.4 M V 2
- RACH Control Parameters 10.5.2.29 M V 3
*/
mLAI.writeV(dest,wp);
mCellSelectionParameters.writeV(dest,wp);
mRACHControlParameters.writeV(dest,wp);
}
void L3SystemInformationType4::text(ostream& os) const
{
L3RRMessage::text(os);
os << "LAI=(" << mLAI << ")";
os << " cellSelectionParameters=(" << mCellSelectionParameters << ")";
os << " RACHControlParameters=(" << mRACHControlParameters << ")";
}
void L3SystemInformationType5::writeBody(L3Frame& dest, size_t &wp) const
{
/*
System Information Type 5, GSM 04.08 9.1.37
- BCCH Frequency List 10.5.2.22 M V 16
*/
mBCCHFrequencyList.writeV(dest,wp);
}
void L3SystemInformationType5::text(ostream& os) const
{
L3RRMessage::text(os);
os << "BCCHFrequencyList=(" << mBCCHFrequencyList << ")";
}
void L3SystemInformationType6::writeBody(L3Frame& dest, size_t &wp) const
{
/*
System Information Type 6, GSM 04.08 9.1.40
- Cell Identity 10.5.1.11 M V 2
- Location Area Identification 10.5.1.3 M V 5
- Cell Options (SACCH) 10.5.2.3 M V 1
- NCC Permitted 10.5.2.27 M V 1
*/
mCI.writeV(dest,wp);
mLAI.writeV(dest,wp);
mCellOptions.writeV(dest,wp);
mNCCPermitted.writeV(dest,wp);
}
void L3SystemInformationType6::text(ostream& os) const
{
L3RRMessage::text(os);
os << "CI=" << mCI;
os << " LAI=(" << mLAI << ")";
os << " cellOptions=(" << mCellOptions << ")";
os << " NCCPermitted=(" << mNCCPermitted << ")";
}
void L3ImmediateAssignment::writeBody( L3Frame &dest, size_t &wp ) const
{
/*
- Page Mode 10.5.2.26 M V 1/2
- Dedicated mode or TBF 10.5.2.25b M V 1/2
- Channel Description 10.5.2.5 C V 3
- Request Reference 10.5.2.30 M V 3
- Timing Advance 10.5.2.40 M V 1
(ignoring optional elements)
*/
// reverse order of 1/2-octet fields
mDedicatedModeOrTBF.writeV(dest, wp);
mPageMode.writeV(dest, wp);
mChannelDescription.writeV(dest, wp);
mRequestReference.writeV(dest, wp);
mTimingAdvance.writeV(dest, wp);
// No mobile allocation in non-hopping systems.
// A zero-length LV. Just write L=0.
dest.writeField(wp,0,8);
}
void L3ImmediateAssignment::text(ostream& os) const
{
os << "PageMode=("<<mPageMode<<")";
os << " DedicatedModeOrTBF=("<<mDedicatedModeOrTBF<<")";
os << " ChannelDescription=("<<mChannelDescription<<")";
os << " RequestReference=("<<mRequestReference<<")";
os << " TimingAdvance="<<mTimingAdvance;
}
void L3ChannelRequest::text(ostream& os) const
{
os << "RA=" << mRA;
os << " time=" << mTime;
}
void L3ChannelRelease::writeBody( L3Frame &dest, size_t &wp ) const
{
mRRCause.writeV(dest, wp);
}
void L3ChannelRelease::text(ostream& os) const
{
L3RRMessage::text(os);
os <<"cause="<< mRRCause;
}
void L3AssignmentCommand::writeBody( L3Frame &dest, size_t &wp ) const
{
mChannelDescription.writeV(dest, wp);
mPowerCommand.writeV(dest, wp);
if (mHaveMode1) mMode1.writeTV(0x63,dest,wp);
}
size_t L3AssignmentCommand::bodyLength() const
{
size_t len = mChannelDescription.lengthV();
len += mPowerCommand.lengthV();
if (mHaveMode1) len += mMode1.lengthTV();
return len;
}
void L3AssignmentCommand::text(ostream& os) const
{
L3RRMessage::text(os);
os <<"channelDescription=("<<mChannelDescription<<")";
os <<" powerCommand="<<mPowerCommand;
if (mHaveMode1) os << " mode1=" << mMode1;
}
void L3AssignmentComplete::parseBody(const L3Frame& src, size_t &rp)
{
mCause.parseV(src,rp);
}
void L3AssignmentComplete::text(ostream& os) const
{
L3RRMessage::text(os);
os << "cause=" << mCause;
}
void L3AssignmentFailure::parseBody(const L3Frame& src, size_t &rp)
{
mCause.parseV(src,rp);
}
void L3AssignmentFailure::text(ostream& os) const
{
L3RRMessage::text(os);
os << "cause=" << mCause;
}
void L3RRStatus::parseBody(const L3Frame& src, size_t &rp)
{
mCause.parseV(src,rp);
}
void L3RRStatus::text(ostream& os) const
{
L3RRMessage::text(os);
os << "cause=" << mCause;
}
void L3ImmediateAssignmentReject::writeBody(L3Frame& dest, size_t &wp) const
{
unsigned count = mRequestReference.size();
assert(count<=4);
dest.writeField(wp,0,4); // spare 1/2 octet
mPageMode.writeV(dest,wp);
for (unsigned i=0; i<count; i++) {
mRequestReference[i].writeV(dest,wp);
mWaitIndication.writeV(dest,wp);
}
unsigned fillCount = 4-count;
for (unsigned i=0; i<fillCount; i++) {
mRequestReference[count-1].writeV(dest,wp);
mWaitIndication.writeV(dest,wp);
}
}
void L3ImmediateAssignmentReject::text(ostream& os) const
{
L3RRMessage::text(os);
os << "pageMode=" << mPageMode;
os << " T3122=" << mWaitIndication;
os << " requestReferences=(";
for (unsigned i=0; i<mRequestReference.size(); i++) {
os << mRequestReference[i] << " ";
}
}
void L3ChannelModeModify::writeBody(L3Frame &dest, size_t& wp) const
{
mDescription.writeV(dest,wp);
mMode.writeV(dest,wp);
}
void L3ChannelModeModify::text(ostream& os) const
{
L3RRMessage::text(os);
os << "description=(" << mDescription << ")";
os << " mode=(" << mMode << ")";
}
void L3ChannelModeModifyAcknowledge::parseBody(const L3Frame &src, size_t& rp)
{
mDescription.parseV(src,rp);
mMode.parseV(src,rp);
}
void L3ChannelModeModifyAcknowledge::text(ostream& os) const
{
L3RRMessage::text(os);
os << "description=(" << mDescription << ")";
os << " mode=(" << mMode << ")";
}
void L3MeasurementReport::parseBody(const L3Frame& frame, size_t &rp)
{
mResults.parseV(frame,rp);
}
void L3MeasurementReport::text(ostream& os) const
{
L3RRMessage::text(os);
os << mResults;
}
// L3ApplicationInformation
L3ApplicationInformation::~L3ApplicationInformation()
{
}
L3ApplicationInformation::L3ApplicationInformation()
{
}
L3ApplicationInformation::
L3ApplicationInformation(BitVector& data, unsigned protocolIdentifier,
unsigned cr, unsigned firstSegment, unsigned lastSegment)
: L3RRMessage(), mID(protocolIdentifier)
, mFlags(cr, firstSegment, lastSegment)
, mData(data)
{
}
void L3ApplicationInformation::writeBody( L3Frame &dest, size_t &wp ) const
{
/*
- APDU ID 10.5.2.48 M V 1/2
- APDU Flags 10.5.2.49 M V 1/2
- APDU Data 10.5.2.50 M LV N
*/
// reverse order of 1/2-octet fields
static size_t start = wp;
LOG(DEBUG) << "L3ApplicationInformation: written " << wp - start << " bits";
mFlags.writeV(dest, wp);
LOG(DEBUG) << "L3ApplicationInformation: written " << wp - start << " bits";
mID.writeV(dest, wp);
LOG(DEBUG) << "L3ApplicationInformation: written " << wp - start << " bits";
mData.writeLV(dest, wp);
LOG(DEBUG) << "L3ApplicationInformation: written " << wp - start << " bits";
}
void L3ApplicationInformation::text(ostream& os) const
{
L3RRMessage::text(os);
os << "ID=("<<mID<<")";
os << " Flags=("<<mFlags<<")";
os << " Data=("<<mData<<")";
}
void L3ApplicationInformation::parseBody(const L3Frame& src, size_t &rp)
{
// reverse order of 1/2-octet fields
mFlags.parseV(src, rp);
mID.parseV(src, rp);
mData.parseLV(src, rp);
}
size_t L3ApplicationInformation::bodyLength() const
{
return 1 + mData.lengthLV();
}
void L3GPRSSuspensionRequest::parseBody(const L3Frame &src, size_t& rp)
{
// We don't really parse this yet.
return;
}
void L3ClassmarkChange::parseBody(const L3Frame &src, size_t &rp)
{
mClassmark.parseLV(src,rp);
mHaveAdditionalClassmark = mAdditionalClassmark.parseTLV(0x20,src,rp);
}
size_t L3ClassmarkChange::bodyLength() const
{
size_t sum = mClassmark.lengthLV();
if (mHaveAdditionalClassmark) sum += mAdditionalClassmark.lengthTLV();
return sum;
}
void L3ClassmarkChange::text(ostream& os) const
{
L3RRMessage::text(os);
os << "classmark=(" << mClassmark << ")";
if (mHaveAdditionalClassmark)
os << " +classmark=(" << mAdditionalClassmark << ")";
}
// vim: ts=4 sw=4