mirror of
https://github.com/RangeNetworks/openbts.git
synced 2025-10-23 07:42:01 +00:00
260 lines
9.2 KiB
C++
260 lines
9.2 KiB
C++
/*
|
|
* Copyright 2011, 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.
|
|
*/
|
|
/**@file GPRS RLC-MAC state machine, GSM 04.60. */
|
|
|
|
/**@file GPRS RLC-MAC state machine, GSM 04.60. */
|
|
|
|
|
|
#ifndef GPRSL2RLCENGINE_H
|
|
#define GPRSL2RLCENGINE_H
|
|
#define INTERNAL_SGSN 1 // Use internal SGSN, no support for BSSG
|
|
#define UPLINK_PERSIST 1
|
|
|
|
|
|
#include <Interthread.h>
|
|
#include <list>
|
|
|
|
#include "GPRSInternal.h"
|
|
#if INTERNAL_SGSN==0
|
|
#include "BSSGMessages.h"
|
|
#endif
|
|
#include "TBF.h"
|
|
#define FAST_TBF 1 // Use aggregated downlink TBFs.
|
|
|
|
namespace GPRS {
|
|
|
|
class PDTCHL1FEC;
|
|
|
|
// Maximum LLC PDU size is 1560 bytes. (GSM04.60 sec9.1.12) Bytes over are discarded in RLC.
|
|
// In unacknowledged mode, LLC-PDUs delivered in the order received, with 0-bits for missing blocks.
|
|
// The minimum payload size (using CS-1) is 20 bytes (see RLCPayloadSize)
|
|
// Therefore, a single PDU may take 78 blocks.
|
|
const int RLC_PDU_MAX_LEN = 1560;
|
|
|
|
|
|
//typedef std::list<BitVector*> LLCSegmentList;
|
|
|
|
class RLCEngineBase
|
|
{
|
|
public:
|
|
// WS => number of blocks sent simultaneously, awaiting ack, before blocking.
|
|
// SNS => must be double WS, by definition.
|
|
static const unsigned mWS = 64; // Window Size
|
|
static const unsigned mSNS = 128; // Sequence Number Space
|
|
|
|
/**@name SN arithmetic */
|
|
int deltaSN(unsigned sn1, unsigned sn2) const;
|
|
int deltaSNS(unsigned sn1, unsigned sn2) const;
|
|
bool deltaEQ(unsigned sn1, unsigned sn2) const;
|
|
unsigned addSN(int sn1, int sn2) const; // Allow negative numbers.
|
|
void incSN(unsigned &psn);
|
|
virtual void engineDump(std::ostream &os) const = 0;
|
|
string engineDumpStr() const { std::ostringstream os; engineDump(os); return os.str(); }
|
|
};
|
|
|
|
enum RlcUpState {
|
|
RlcUpTransmit,
|
|
RlcUpQuiescent,
|
|
RlcUpPersistFinal,
|
|
RlcUpFinished,
|
|
};
|
|
|
|
// (pat) This is an RLC endpoint as per GSM 04.60 9.1
|
|
// It sits in layer 2.
|
|
class RLCUpEngine : public TBF, public RLCEngineBase
|
|
{
|
|
protected:
|
|
/**@name RLC state variables, from GSM 04.60 9. */
|
|
// We depend on the MS not to send us blocks with BSN > VQ+mWS, and inform
|
|
// the MS of our concept of VQ in the acknack we send.
|
|
// However, the only way we know the acknack is received may be that the MS
|
|
// sends more blocks.
|
|
struct {
|
|
unsigned VR; ///< highest BSN received + 1 modulo wSNS;
|
|
// 0 <= VR <= wSNS-1;
|
|
unsigned VQ; ///< lowest BSN not yet received (window base)
|
|
// In acknowledged mode, receive window is
|
|
// defined by: VQ <= BSN <= VQ + mWS
|
|
bool VN[mSNS]; ///< receive status of previous RLC data blocks
|
|
RLCUplinkDataBlock *RxQ[mSNS]; ///< assembly queue for inbound RLC data blocks
|
|
//unsigned RBSN; ///< BSN of incoming blocks.
|
|
} mSt;
|
|
//@}
|
|
|
|
#if INTERNAL_SGSN
|
|
ByteVector *mUpPDU; // The PDU being assembled.
|
|
#else
|
|
BSSG::BSSGMsgULUnitData *mUpPDU; // The PDU being assembled.
|
|
#endif
|
|
Bool_z mIncompletePDU; // Special case: If set, the PDU did not finish in this TBF;
|
|
// MS needs another TBF to send the rest of it.
|
|
// Dont think we need this if using unlimited dynamic mode uplink.
|
|
Bool_z mUpStalled; // MS is stalled, copied from each uplink block header.
|
|
|
|
static const unsigned mNumUpPerAckNack = 10;
|
|
UInt_z mNumUpBlocksSinceAckNack; // Number of blocks sent since the last acknack
|
|
UInt_z mTotalBlocksReceived;
|
|
UInt_z mUniqueBlocksReceived;
|
|
int mBytesPending;
|
|
#if UPLINK_PERSIST
|
|
RLCBSN_t mDataPersistFinalEndBSN; // When DataPersistFinal mode started.
|
|
bool mUpPersistentMode;
|
|
GprsTimer mtUpKeepAliveTimer; // Time to next keep alive.
|
|
GprsTimer mtUpPersistTimer; // How long TBF persists while idle.
|
|
#endif
|
|
|
|
// The MS keeps a running total of USF slots granted to the MS.
|
|
// The difference between the current value and the starting value divided
|
|
// by the number of unique blocks received is a measure of the loss ratio,
|
|
// although that breaks down if there are multiple simultaneous uplink TBFs.
|
|
unsigned mStartUsfGrants;
|
|
//unsigned mNumServiceSlotsSkipped; // Reality check disaster recovery.
|
|
RlcUpState mtUpState; // Set after all blocks have been received.
|
|
|
|
public:
|
|
RLCUpEngine(MSInfo *wms,int wOctetCount);
|
|
~RLCUpEngine();
|
|
|
|
void addUpPDU(BitVector&);
|
|
void sendPDU();
|
|
bool stalled() const { return mUpStalled; }
|
|
#if UPLINK_PERSIST
|
|
bool ulPersistentMode();
|
|
bool sendNonFinalAckNack(PDCHL1Downlink *down);
|
|
#endif
|
|
|
|
void engineRecvDataBlock(RLCUplinkDataBlock* block, int tn);
|
|
void engineUpAdvanceWindow();
|
|
bool engineService(PDCHL1Downlink *down); // Thats right: we pass the downlink.
|
|
float engineDesiredUtilization();
|
|
void engineDump(std::ostream &os) const;
|
|
void engineGetStats(unsigned *pSlotsTotal, unsigned *pSlotsUsed, unsigned *pGrants) const {
|
|
*pSlotsTotal = mTotalBlocksReceived;
|
|
*pSlotsUsed = mUniqueBlocksReceived;
|
|
*pGrants = mtMS->msNumDataUSFGrants - mStartUsfGrants;
|
|
}
|
|
int engineGetBytesPending() { return mBytesPending; }
|
|
RLCMsgPacketUplinkAckNack * engineUpAckNack();
|
|
TBF *getTBF() { return dynamic_cast<TBF*>(this);}
|
|
};
|
|
|
|
class RLCDownEngine : public TBF, public RLCEngineBase
|
|
{
|
|
public:
|
|
|
|
/**@name RLC state variables, from GSM 04.60 9. */
|
|
//@{
|
|
struct {
|
|
unsigned VS; ///< BSN of next RLC data block for tx
|
|
// After receipt of acknack message, VS is set back to VA.
|
|
unsigned VA; ///< BSN of oldest un-acked RLC data block
|
|
bool VB[mSNS]; ///< ack status of pending RLC data blocks (true = acked)
|
|
RLCDownlinkDataBlock *TxQ[mSNS]; ///< unacked RLC data blocks saved for re-tx
|
|
//int sendTime[mSNS]; ///<RLCBSN when block was first sent.
|
|
// VCS is used for multi-block Control Messages, so does not apply to us.
|
|
// bool VCS; ///< 0 or 1 indicating state for multi-block RLC control messages.
|
|
unsigned TxQNum; // One greater than last block in queue. It wraps around.
|
|
} mSt;
|
|
//@}
|
|
// This is additional state:
|
|
UInt_z mPrevAckSsn; // The SSN of the previous downlinkAckNack.
|
|
UInt_z mResendSsn; // Resend blocks with SN less than this.
|
|
UInt_z mPrevAckBlockCount; // Saves value of mTotalBlocksSent from last downlinkAckNack.
|
|
|
|
Bool_z mDownStalled; // Yes, set when the downlink is stalled.
|
|
Bool_z mDownFinished; // Set when we have sent the block with the FBI indicator.
|
|
Bool_z mAllAcked; // Have all the blocks been acked?
|
|
UInt_z mNumDownBlocksSinceAckNack;
|
|
unsigned mNumDownPerAckNack;
|
|
UInt_z mTotalBlocksSent; // Total sent; some of them may have been lost in transmission
|
|
UInt_z mTotalDataBlocksSent; // Number of blocks in the TBF.
|
|
UInt_z mUniqueDataBlocksSent; // Number of blocks in the TBF.
|
|
|
|
#if INTERNAL_SGSN==0
|
|
// BSSG no longer used:
|
|
BSSG::BSSGMsgDLUnitData *mBSSGDlMsg; // The downlink message that created this TBF.
|
|
#endif
|
|
// We save it because the RLCEngine has a pointer into it,
|
|
// and delete it when we delete the TBF.
|
|
ByteVector mDownPDU; // The PDU part of mBSSGDlMsg. Automatic destruction.
|
|
SGSN::GprsSgsnDownlinkPdu *mDownlinkPdu; // This is the most recent sdu sent in the TBF.
|
|
// We keep it around so we can retry the TBF if necessary.
|
|
|
|
// Moved to class TBF:
|
|
GprsTimer mtDownKeepAliveTimer; // Time to next keep alive.
|
|
GprsTimer mtDownPersistTimer; // How long TBF persists while idle.
|
|
|
|
|
|
RLCDownEngine(MSInfo *wms) :
|
|
TBF(wms,RLCDir::Down),
|
|
#if INTERNAL_SGSN==0
|
|
mBSSGDlMsg(0), // No longer used.
|
|
#endif
|
|
mDownlinkPdu(0)
|
|
{
|
|
memset(&mSt,0,sizeof(mSt));
|
|
mNumDownPerAckNack = gConfig.getNum("GPRS.TBF.Downlink.Poll1");
|
|
}
|
|
~RLCDownEngine();
|
|
|
|
// Is the downlink engine stalled, waiting for acknack messages?
|
|
bool stalled() const { return mDownStalled; }
|
|
//bool finished() { return mSt.VS >= mSt.TxQNum; }
|
|
unsigned engineDownPDUSize() const { return mDownPDU.size(); }
|
|
|
|
RLCDownlinkDataBlock *getBlock(unsigned vs,int tn);
|
|
void engineWriteHighSide(SGSN::GprsSgsnDownlinkPdu *dlmsg); // TODO: get rid of this.
|
|
bool dlPersistentMode(); // Are we using persistent TBF mode?
|
|
bool dataAvail(); // Is more downlink data available?
|
|
RLCDownlinkDataBlock* engineFillBlock(unsigned bsn,int tn);
|
|
void engineRecvAckNack(const RLCMsgPacketDownlinkAckNack*);
|
|
bool engineService(PDCHL1Downlink *down);
|
|
float engineDesiredUtilization();
|
|
void engineDump(std::ostream &os) const;
|
|
void engineGetStats(unsigned *pSlotsTotal, unsigned *pSlotsUsed, unsigned *pGrants) const {
|
|
// We dont care about the control blocks sent, only the data.
|
|
//*pSlotsTotal = mTotalBlocksSent; // Number of blocks we have sent.
|
|
*pSlotsTotal = mTotalDataBlocksSent; // Number of blocks we have sent.
|
|
*pSlotsUsed = mUniqueDataBlocksSent; // Number of blocks MS has acknowledged.
|
|
*pGrants = 0; // Inapplicable to downlink.
|
|
}
|
|
int engineGetBytesPending() { return 0; } // TODO, but it is a negligible amount
|
|
//bool isLastUABlock();
|
|
//unsigned blocksToGo();
|
|
bool resendNeeded(int bsn);
|
|
void advanceVS();
|
|
void advanceVA();
|
|
TBF *getTBF() { return dynamic_cast<TBF*>(this);}
|
|
};
|
|
|
|
|
|
|
|
// This incorporates both an up and down engine, but only one of them is used.
|
|
//class RLCEngine :
|
|
// public RLCUpEngine,
|
|
// public RLCDownEngine
|
|
//{
|
|
// public:
|
|
// RLCEngine(TBF *);
|
|
// ~RLCEngine();
|
|
//};
|
|
|
|
|
|
}; // namespace GPRS
|
|
|
|
|
|
|
|
#endif
|