/**@file @brief Radio Resource messages, GSM 04.08 9.1. */ /* * Copyright 2008, 2009 Free Software Foundation, Inc. * Copyright 2010, 2013 Kestrel Signal Processing, Inc. * Copyright 2014 Range Networks, Inc. * * This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution. * * 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. */ #define LOG_GROUP LogGroup::GSM // Can set Log.Level.GSM for debugging #include // for L3APDUData::text #include "GSML3RRElements.h" #include "Defines.h" #include "GSMConfig.h" #include using namespace std; namespace GSM { L3ControlChannelDescription *gControlChannelDescription = NULL; void L3CellOptionsBCCH::writeV(L3Frame& dest, size_t &wp) const { dest.writeField(wp,0,1); dest.writeField(wp,mPWRC,1); dest.writeField(wp,mDTX,2); dest.writeField(wp,mRADIO_LINK_TIMEOUT,4); } void L3CellOptionsBCCH::text(ostream& os) const { os << "PWRC=" << mPWRC; os << " DTX=" << mDTX; os << " RADIO_LINK_TIMEOUT=" << mRADIO_LINK_TIMEOUT; } void L3CellOptionsSACCH::writeV(L3Frame& dest, size_t &wp) const { dest.writeField(wp,(mDTX>>2)&0x01,1); dest.writeField(wp,mPWRC,1); dest.writeField(wp,mDTX&0x03,2); dest.writeField(wp,mRADIO_LINK_TIMEOUT,4); } void L3CellOptionsSACCH::text(ostream& os) const { os << "PWRC=" << mPWRC; os << " DTX=" << mDTX; os << " RADIO_LINK_TIMEOUT=" << mRADIO_LINK_TIMEOUT; } void L3CellSelectionParameters::writeV(L3Frame& dest, size_t &wp) const { dest.writeField(wp,mCELL_RESELECT_HYSTERESIS,3); dest.writeField(wp,mMS_TXPWR_MAX_CCH,5); dest.writeField(wp,mACS,1); dest.writeField(wp,mNECI,1); dest.writeField(wp,mRXLEV_ACCESS_MIN,6); } void L3CellSelectionParameters::text(ostream& os) const { os << "CELL-RESELECT-HYSTERESIS=" << mCELL_RESELECT_HYSTERESIS; os << " MS-TXPWR-MAX-CCH=" << mMS_TXPWR_MAX_CCH; os << " ACS=" << mACS; os << " NECI=" << mNECI; os << " RXLEV-ACCESS-MIN=" << mRXLEV_ACCESS_MIN; } L3ControlChannelDescription::L3ControlChannelDescription() : L3ProtocolElement() { mCCCH_CONF=gConfig.getNum("GSM.CCCH.CCCH-CONF"); string bs_ag_blks_res = gConfig.getStr("GSM.CCCH.BS_AG_BLKS_RES"); if (bs_ag_blks_res == "auto") { if (mCCCH_CONF == 1) { mBS_AG_BLKS_RES=2; // reserve 2 CCCHs for access grant (meaning 1 for paging) } else { mBS_AG_BLKS_RES=7; // reserve 7 CCCHs for access grant (meaning 2 for paging) } } else { mBS_AG_BLKS_RES = atoi(bs_ag_blks_res.c_str()); } mBS_PA_MFRMS = gConfig.getNum("GSM.CCCH.BS_PA_MFRMS"); // Number of paging multiframes. Default is 2, the minimum allowed value. // Configurable values. mATT=(unsigned)gConfig.getBool("Control.LUR.AttachDetach"); mT3212=gConfig.getNum("GSM.Timer.T3212")/6; } void L3ControlChannelDescription::validate() { if (mBS_PA_MFRMS != RN_BOUND(mBS_PA_MFRMS,2,9)) { LOG(ERR) << "Invalid BS_PA_MFRMS value, must be 2..9"; mBS_PA_MFRMS = 2; // If invalid, it is ok as long as we use the same value all the time. } switch (mCCCH_CONF) { // Type 1 is the original beacon config used by Range. case 1: // Timeslot C0 with 3 CCCH and 4 SDCCH. if (mBS_AG_BLKS_RES != RN_BOUND(mBS_AG_BLKS_RES,0,2)) { LOG(ERR) << "Invalid BS_AG_BLKS_RES value, must be 0..2"; mBS_AG_BLKS_RES = 7; } break; default: LOG(ERR) << "Invalid GSM.CCCH.CCCH-CONF value:"< output( os, "" ); //std::copy( mData.begin(), mData.end(), output ); os <<"data(size="< BCCH Norm } else { dest.writeL(wp); } while (wp & 7) { dest.writeL(wp); } // spare padding to byte boundary. assert(wp-wpstart == lengthV() * 8); } void L3SI3RestOctets::text(ostream& os) const { if (!mHaveSI3RestOctets) { return; } if (mHaveSelectionParameters) { os << "CBQ=" << mCBQ; os << " CELL_RESELECT_OFFSET=" << mCELL_RESELECT_OFFSET; os << " TEMPORARY_OFFSET=" << mTEMPORARY_OFFSET; os << " PENALTY_TIME=" << mPENALTY_TIME; } if (mHaveGPRS) { os << " RA_COLOUR=" << mRA_COLOUR; } } void L3HandoverReference::writeV(L3Frame& frame, size_t& wp) const { frame.writeField(wp,mValue,8); } size_t L3CipheringModeSetting::lengthV() const { return 0; } void L3CipheringModeSetting::writeV(L3Frame& frame, size_t& wp) const { frame.writeField(wp, mCiphering? mAlgorithm-1: 0, 3); frame.writeField(wp, mCiphering, 1); } void L3CipheringModeSetting::text(ostream& os) const { os << "ciphering=" << mCiphering; os << " algorithm=A5/" << mAlgorithm; } size_t L3CipheringModeResponse::lengthV() const { return 0; } void L3CipheringModeResponse::writeV(L3Frame& frame, size_t& wp) const { frame.writeField(wp, 0, 3); frame.writeField(wp, mIncludeIMEISV, 1); } void L3CipheringModeResponse::text(ostream& os) const { os << "includeIMEISV=" << mIncludeIMEISV; } void L3HandoverReference::text(ostream& os) const { os << "value=" << mValue; } void L3SynchronizationIndication::writeV(L3Frame& frame, size_t& wp) const { frame.writeField(wp,0xD,4); frame.writeField(wp,mNCI,1); frame.writeField(wp,mROT,1); frame.writeField(wp,mSI,2); } void L3SynchronizationIndication::parseV( const L3Frame &src, size_t &rp) { src.readField(rp, 4); mNCI = src.readField(rp, 1); mROT = src.readField(rp, 1); mSI = src.readField(rp, 2); } void L3SynchronizationIndication::text(ostream& os) const { os << "NCI=" << (int)mNCI << " ROT=" << (int)mROT << " SI=" << mSI; } void L3CellDescription::writeV(L3Frame& frame, size_t &wp) const { frame.writeField(wp, mARFCN>>8, 2); frame.writeField(wp, mNCC, 3); frame.writeField(wp, mBCC, 3); frame.writeField(wp, mARFCN & 0x0ff, 8); } void L3CellDescription::parseV(const L3Frame&src, size_t&rp) { unsigned arfcnHighBits = src.readField(rp,2); mNCC = src.readField(rp,3); mBCC = src.readField(rp,3); mARFCN = src.readField(rp,8) + (arfcnHighBits<<8); } void L3CellDescription::text(std::ostream& os) const { os << " ARFCN=" << mARFCN; os << " NCC=" << mNCC; os << " BCC=" << mBCC; } void L3SI13RestOctets::writeV(L3Frame& dest, size_t &wp) const { size_t wpstart = wp; dest.writeH(wp); // Indicates Rest Octets are present. // (pat) We support the changemark while OpenBTS is running, but on OpenBTS // startup the changemark is always the same value, so if you kill OpenBTS, // change something that affects the beacon, and restart, the MS does not read // the changed beacon because the changemark is the same. dest.writeField(wp,gBTS.changemark()%8,3); // BCCH_CHANGE_MARK dest.writeField(wp,0,4); // SI13_CHANGE_FIELD dest.writeField(wp,0,1); // no changemark or mobile allocation // (pat) The GPRS "mobile allocation" is optional and does // not indicate that GPRS service is present or absent. dest.writeField(wp,0,1); // no PBCCH (pat says: This is correct.) dest.writeField(wp,mRAC,8); dest.writeField(wp,mSPGC_CCCH_SUP,1); dest.writeField(wp,mPRIORITY_ACCESS_THR,3); dest.writeField(wp,mNETWORK_CONTROL_ORDER,2); mCellOptions.writeBits(dest,wp); mPowerControlParameters.writeBits(dest,wp); while (wp & 7) { dest.writeL(wp); } // spare padding to byte bondary. assert(wp-wpstart == lengthV() * 8); } void L3SI13RestOctets::text(ostream& os) const { os << "RAC=" << mRAC; os << " SPGC_CCCH_SUP=" << mSPGC_CCCH_SUP; os << " PRIORITY_ACCESS_THR=" << mPRIORITY_ACCESS_THR; os << " NETWORK_CONTROL_ORDER=" << mNETWORK_CONTROL_ORDER; os << " cellOptions=(" << mCellOptions << ")"; os << " powerControlParameters=(" << mPowerControlParameters << ")"; } } // namespace GSM // vim: ts=4 sw=4