OpenBTS-UMTS/UMTS/MACEngine.h

534 lines
19 KiB
C++

/**@file UMTS MAC, 3GPP 25.321. */
/*
* OpenBTS provides an open source alternative to legacy telco protocols and
* traditionally complex, proprietary hardware systems.
*
* Copyright 2011, 2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero General
* Public License version 3. See the COPYING and NOTICE files in the main
* directory for licensing information.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
*/
#ifndef L2MACENGINE_H
#define L2MACENGINE_H
#include <Interthread.h>
//#include <Configuration.h>
#include <ByteVector.h>
#include <list>
#include <Defines.h>
#include "URRCDefs.h"
#include "UMTSTransfer.h"
#include "UMTSCommon.h" // For L1FEC_t
#define USE_CCCH_Q 0
#if 0
Questions:
o Rate Matching - UL can zero-pad messages, but DL cannot.
Without rate matching CCTrCh must be exact radio size or 0.
o Who is doing the USIM L3 negotiation?
#endif
namespace UMTS {
class MacEngine;
class UEInfo;
class MaccBase;
class MacdBase;
class RrcTfc;
class RrcTfcs;
class RrcMasterChConfig;
class URlcTransUm;
class DCHFEC;
class RACHFEC;
class FACHFEC;
typedef DCHFEC DCHFEC_t;
extern unsigned macHeaderSize(TrChType trch, ChannelTypeL3 ltype, bool multiplexing);
extern unsigned macHeaderSize(TrChType trch, int rbid, bool multiplexing);
extern void macHookupRachFach(RACHFEC *rach, FACHFEC *fach, bool useForCcch);
extern void macHookupDch(DCHFEC_t *dch, UEInfo *uep);
extern void macUnHookupDch(UEInfo *uep);
class MacTbDl : public TransportBlock
{
public:
MacTbDl(unsigned wTBSize) : TransportBlock(wTBSize) {}
};
// Note: If BCCH were sent of FACH, then a special header would be added, but we dont do that.
// We send BCCH over BCH, and there is no header at all, so there is no class here;
// it just uses TransportBlock directly, and bypasses RLC and MAC entirely.
// Used for CCCH, which may be sent only on Mac-c: common channel SCCPCH.
struct MaccTbDlCcch : public MacTbDl
{
MaccTbDlCcch(unsigned trbksize,ByteVector *pdu);
};
// Used for DCCH or DTCH when sent on Mac-c: common channel SCCPCH.
struct MaccTbDl : public MacTbDl
{
MaccTbDl(unsigned trbksize,ByteVector *pdu, UEInfo *uep, RbId rbid);
};
// Used for DCCH or DTCH when sent on Mac-d: dedicated channel DCH.
struct MacdTbDl : public MacTbDl
{
MacdTbDl(unsigned trbksize, ByteVector *pdu, RbId rbid, bool multiplexed);
};
// Uninteresting class, but the name itself is documentation about which way it is traveling.
struct MacTbUl : public TransportBlock
{
MacTbUl(const TransportBlock &tb) : TransportBlock(tb) {} // great language
MacTbUl(const MacTbUl &tb) : TransportBlock(static_cast<TransportBlock>(tb)) {}
};
// This accumulates the information for a Transport Format Combination match
// when the MAC is trying to find a TFC that matches the data available to send in a UE.
struct TfcMap
{
RrcTfc *mtfc;
struct TcMap {
unsigned mNumTbAvail;
unsigned mChIdMap[RrcDefs::maxTbPerTrCh]; // Logical channel where TBs are coming from.
} mtc[RrcDefs::maxTrCh];
unsigned getNumTbAvail(TrChId tcid) { return mtc[tcid].mNumTbAvail; }
void tfcMapClear() {
mtfc = 0;
for (unsigned i = 0; i < RrcDefs::maxTrCh; i++) {mtc[i].mNumTbAvail = 0;}
}
// Return true if the map is full so the caller can stop looking.
bool tfcMapAdd(TrChId tcid,int lcid,int numTB) {
TcMap *ptc = &mtc[tcid];
for (int i = 0; i < numTB; i++) {
if (ptc->mNumTbAvail >= RrcDefs::maxTbPerTrCh) { return true; }
ptc->mChIdMap[ptc->mNumTbAvail++] = lcid;
}
return false;
}
};
// The MAC implementation has four variations arranged in a 2x2 matrix.
// There are two channel types supported:
// 1. MAC for DCH (logical DCCH+DTCH) dedicated channels,
// 2. MAC for PRACH/SCCPCH (logical RACH/FACH) common channels.
// For each of the above, there are two variations:
// 1. Simple version - simple version sends single TransportBlock to Layer1.
// 2. WithTfc version - complex version sends MacTbs to Layer1.
// Whoever sets up the stack should glue an appropriate MAC class to the top
// of the Layer 1 TrCHFEC class.
// The Simple version is a simplified MAC implementation that assumes
// a single TrCh and sends only a single TransportBlock down to the PHY layer class TrCHFEC.
// That means either:
// o there is no CTFC broadcast on the channel, meaning that blind detection is employed.
// Blind detection could be based on either presence/absence of the data
// (meaning just one tbsize) or optionally multiple rlc sizes using a method
// so complicated that we will probably never use it.
// o or there could be a CTFC selected by the PHY layer based solely on the TransportBlock size,
// however, that would be a weird partitioning of the duties between MAC and L1.
//
// The WithTfc version is a full-bore implementation of everything.
// There were lots of other sub-possibilities of MAC implementations, but once
// you are doing TFCS selection, it is no extra trouble to implement the whole
// shebang here at the MAC level and let the PHY layer only pick out the data it wants,
// which it knows will be correct because we control the TFS setups via the RRC setup classes.
// The MacTbs is what MAC sends to the PHY channel for the full-bore implementation.
// Most generally, the TBS consists of a TFCS that selects a TransportFormat for each TrCh,
// plus a set of TransportBlocks for each TrCh channel.
//
// A TBS sent on Mac-C for FACH.
// I dont think all the possible TfcMap possibilities are legal,
// but this just does whatever is programmed by RRC.
class MaccTbs : public MacTbs
{ public:
// Fill the TBS with data from this UE.
// The logical channel from which to send data is in the map.
MaccTbs(UEInfo *uep, TfcMap &map);
};
// A TBS consisting of a single TransportBlock on channel 0.
// Used for CCCH.
class MacTbsSingle : public MacTbs
{ public:
MacTbsSingle(RrcTfc *tfc, TransportBlock *tb);
};
#if MAC_IMPLEMENTATION
MacTbsSingle::MacTbsSingle(RrcTfc *tfc, TransportBlock *tb) : MacTbs(tfc) {
addTb(tb);
}
#endif
// A TBS sent on Mac-D for DCH.
class MacdTbs : public MacTbs
{ public:
// Fill the TBS with data from this UE.
// The logical channel from which to send data is in the map.
MacdTbs(UEInfo *uep, TfcMap &map);
};
// The low side of MAC uses TransportBlocks (possibly inside MacTbs) for uplink and downlink.
// The high side of MAC uses ByteVectors for downlink (except for BCH, which bypasses MAC)
// and BitVectors for uplink. See URLC.h for explanation.
// The data channels are all pulled from below on demand, with the exception of CCCH messages
// which bypass RLC.
// gMacSwitch is the only MacSwitch object.
class MacSwitch
{
typedef std::list<MaccBase*> CchList_t; // For common channels.
//typedef std::list<MacdBase*> DchList_t; // For dedicated channels.
// A list of all the MAC entities that want service, and a lock for the list.
typedef std::list<MacEngine*> MacList_t;
Mutex mMacListLock;
MacList_t mMacList;
Bool_z mStarted; // Is the macServiceLoop running?
Thread macThread; // The mac service loop thread.
static void *macServiceLoop(void *arg);
CchList_t mCchList; // Common channels, ie, one RACH/FACH. Might be only one.
// This has to be an ordered list so we can pick the proper
// FACH channel based on URNTI.
//DchList_t mDchList; // Not used. Dedicated channels, ie, associated with a UE.
public:
// Add, remove, macs from the list of active macs.
void addMac(MacEngine *mac, bool useForCcch);
void rmMac(MacEngine *mac);
MaccBase *pickFachMac(unsigned urnti);
void macWriteLowSideRach(const MacTbUl&tb);
//void writeHighSideBch(ByteVector *msg); // Not used - MAC bypassed entirely.
void writeHighSideCcch(ByteVector &sdu, const std::string descr); // Goes out on a FACH channel.
// There is no writeHighSideDCCH or writeHighSideDTCH here.
// Those messages go directly to an RLC entitiy in the UEInfo
// Dont think we will use this here either:
//void writeLowSideDch(const MacTbUl &tb,UEInfo *uep);
};
extern MacSwitch gMacSwitch;
// These little tiny MAC classes are for David to glue on to the top of the TrChFEC classes.
// Note that the whole conceptual point of MAC is to switch data between different channels,
// so the bulk of MAC is in the MacSwitch.
// Various notes:
// o For RACH, if there are multiple ones we dont care
// which one sent us the TransportBlock, they are all equivalent.
// o For FACH, if there may be muliple ones we pick one based on URNTI.
// o I recommended that we have different types of RACH/FACH channels for different PDU sizes.
// o Control information for a UE may switch from FACH to DCH.
// o For DCH, tying MAC to a particular TrChFEC is ok, but the RLC engines are per-UE.
// Defines the downstream interface to L1, a base class for TrCHFEC and L1CCTrCh
//class MacL1FecInterface {
// public:
// virtual unsigned getNumRadioFrames() const;
// virtual void writeHighSide(const TransportBlock& frame);
// virtual unsigned getDlTrBkSz() const;
//};
static void shut_up_gcc(int) {}
// This is the class referenced in class TrCHFEC.
class MacEngine
{
protected:
// Temporary hack: Use two downstream pointers while we are debugging the L1CCTrCh, and use whichever is non-NULL.
TrCHFEC * mDownstream;
L1CCTrCh * mccDownstream;
public:
MacEngine() : mDownstream(0), mccDownstream(0) { }
void macSetDownstream(TrCHFEC *wDownstream) { mDownstream = wDownstream; }
void macSetDownstream(L1CCTrCh *wccDownstream) { mccDownstream = wccDownstream; }
unsigned macGetDlNumRadioFrames() const;
void macWriteHighSide(MacTbDl &tb);
unsigned macGetDlTrBkSz();
// There are two different writeLowSide methods depending on MAC complexity.
// They are only defined in their respective final classes.
virtual void macWriteLowSideTb(const TransportBlock&,TrChId tcid=0) { assert(0); shut_up_gcc(tcid); }
virtual void macService(int fn) = 0;
};
// Sends/receives TransportBlocks of just one size.
class MacSimple : public virtual MacEngine
{
public:
// redundant: virtual void macWriteLowSideTb(const TransportBlock&tb) = 0;
void sendDownstreamTb(MacTbDl &tb);
};
// Sends/receives MacTbs [Transport Block Set] which includes a TFC [Transport Format Combination]
// Also supports multiple TrCh, which was no extra effort.
class MacWithTfc : public virtual MacEngine
{ protected:
void findTbAvail(UEInfo *uep, TfcMap *map);
bool matchTfc(RrcTfc *tfc, UEInfo *uep, TfcMap *match);
public:
bool findTfcForUe(UEInfo *uep,TfcMap *result);
RrcTfc *findTfcOfTbSize(RrcTfcs *tfcs, TrChId tcid, unsigned tbsize);
void sendDownstreamTbs(MacTbs &tbs);
};
// MAC-d handles DCH.
// The only point of it is to associate a UEInfo with an L1 TrCh processor.
// (pat) TODO: This is not fully implemented yet.
class MacdBase : public virtual MacEngine
{ protected:
UEInfo *mUep;
//bool macMultiplexed[RrcDefs::maxTrCh];
//RbId macRbId[RrcDefs::maxTrCh]; // If multiplexed == false this is the rbid.
//Thread macThread;
// Flush any TransportBlocks in the UE associated with this DCH.
virtual bool flushUE() = 0;
public:
MacdBase(UEInfo *wUep) : mUep(wUep) {
//memset(macMultiplexed,0,sizeof(macMultiplexed));
//memset(macRbId,0,sizeof(macRbId));
}
// Same service loop works for both descendent classes.
//static void *macServiceLoop(void*);
//void macStart();
void macService(int fn);
};
class MacdSimple : public MacdBase, public MacSimple
{
// This class handles just a single TrCh.
// Either it is multiplexed or it is assigned to a specific rb.
// (pat) macRbId is not used. If we are not multiplexed we will be using class MacdWithTfc.
bool flushUE();
bool macMultiplexed; // We always use this multiplexed, so this is redundant.
RbId macRbId; // This is not used.
public:
MacdSimple(UEInfo *wUep, bool wMultiplexed, RbId wrbid) : MacdBase(wUep)
{ macMultiplexed = wMultiplexed; macRbId = wrbid; }
void macWriteLowSideTb(const TransportBlock&tb, TrChId tcid=0);
};
class MacdWithTfc : public MacdBase, public MacWithTfc
{ public:
bool flushUE();
MacdWithTfc(UEInfo *wUep) : MacdBase(wUep) {}
void macWriteLowSideTb(const TransportBlock&tb, TrChId tcid=0);
};
class MaccBase : public virtual MacEngine
{
protected:
// Where is the RLC for CCCH messages? Not clear.
// The MAC spec says that RLC is connected to the top of MAC
// per logical channel, which would imply there is one UM-RLC entity per RNC.
// However, CCCH can switched to multiple different FACH, so that doesnt really make sense.
// UEs that are listening to different FACH would not know or care if there were
// other FACHs around, so I am implementing with one RLC per Macc engine
// for the CCCH messages sent on that FACH, and here it is:
URlcTransUm *mCcchRlc;
//Thread macThread;
virtual bool flushUE()=0;
virtual bool flushQ()=0;
//static void *macServiceLoop(void*);
//void macStart();
void macService(int fn);
#if USE_CCCH_Q // Not using this now - using mCcchRlc instead.
// PDUs waiting to be sent normally sit in the queue at the high end of an RLC
// and wait until they get pulled.
// CCCH is an exception - they are pushed through RLC and wait here,
// and this Q is written first before we look for other data.
// CCCH is special in several ways:
// It is not associated with any UE, and if there are several FACH,
// data may be broadcast in several CCCH queues simultaneously.
// The MAC header is prepended before adding to the queue, in other words,
// these are TransportBlocks all ready to go.
InterthreadQueue<MaccTbDlCcch> mTxCcchQ;
#endif
public:
// TODO: Constructor?
// Write a CCCH message to this channel.
//void writeHighSideCcch(MaccTbDlCcch *tb);
void writeHighSideCcch(ByteVector &sdu, const std::string descr);
};
// MAC-c handles RACH or FACH.
// The only point of it is to put a handle on a TrCHFEC used for RACH/FACH.
// Uplink messages go to a common queue for processing.
//
// If there are multiple FACH, downlink messages go to a FACH based on
// (UE-id mod (number of FACH channels)).
// For connected mode, 25.331 8.5.19 says UE-id is URNTI.
// For unconnected mode, ie, for the RRC Connection Request
// and RRC Connection Setup messages on CCCH, 25.304 8.2 defines UE-id
// based on the "IntialUE_Identity" and has many different cases.
// Currently We just blast the message out on all FACH in use for unconnected mode.
//
// CCCH messages do not have much of a MAC header, but they still must use a TFC if the
// same phy channel is used for any other tbsizes. In the latter case, they
// use the exact same processing as any other MAC channel.
//
// The simplified MaccSimple assumes all pdus are the same size, ignores priority.
// It may have a TFC with just two entries to indicate presence or absence.
class MaccSimple : public MaccBase, public MacSimple
{
bool flushUE();
bool flushQ();
void macWriteLowSideTb(const TransportBlock&tb, TrChId tcid=0);
public:
MaccSimple(unsigned trbksize);
};
class MaccWithTfc : public MaccBase, public MacWithTfc
{
bool flushUE();
bool flushQ();
public:
MaccWithTfc(unsigned trbksize);
// Check all the UEs that can use this FACH to see if they have something to send.
void macWriteLowSideTb(const TransportBlock&tb, TrChId tcid=0);
void macWriteLowSideTbs(const MacTbs&/*tbs*/) {
// TODO. We may never use this.
}
};
// We dont need a Mac-b class - BCH bypasses MAC entirely.
//class MACbEngine : public virtual MacEngine {
// virtual void writeHighSide(const RLCSDU&);
// void macWriteLowSide(const TransportBlock&) { assert(0); }
//};
} // namespace UMTS
// Pats in-progress now-obsolete notes below.
// I kept these while I was trying to figure this out, and they are probably
// useless now, but I loathe discarding any information whatever.
//
// GSM 25.331: RRC Protocol Spec.
// 10.3.5.1: Added or reconfigured DL TrCH info
// The UL and DL can be the same or different.
// UL & DL Type (DSCH)
// UL & DL Transport Channel ID 10.3.5.18
// TFS Transport Format Set 10.3.5.23
// UL & DL TrCH Id
// MAC header type (choice of ...)
// DCH Quality Target. 10.3.5.10 real(-6.3..0)
//
// 10.3.5.24: UL Transport Ch Info common for All TrCh.
// Looks unused in this version of the protocol.
// TFC subsets for various channels and TFCS ids.
//
// 10.3.5.11: Semi-Static Transport Format Info
// TTI integer(10,20,40,80)
// ChannelCoding enum(None,Convolutional, Turbo)
// CodingRate enum(1/2,1/3)
// RateMatching Attribute integer(1..hi RM)
// CRCsize integer(0,8,12,16,24)
// 10.3.5.15 TFCS Complete Reconfig/Addition Information
// It is a big union depending on TFCI size (number of bits in TFC, maybe 4,8,1,6,32)
// Power Offset Info 10.3.5.8 (needed only for UL physical channels)
// MAC does not perform segmentation on DCH, only only on MAC-e/es, MAC-hs/ehs, MAC-i/is
// Same with HARQ - Hybrid Automatic Repeat Request.
//
// Notes:
// RABs are 8 bits, used within a CN (Core Network) domain.
// RB ids are 1..32, used with a single RNC I guess.
// Logical channel ids are 1..15 "Used to distinguish logical channels multiplexed
// by MAC on a transport channel."
// 10.3.5.23: Tranport Format Set
// GSM25.212 says:
// "Uplink [and Downlink] Dedicated Channel (DCH):
// The maximum value of the number of TrCHs I in a CCTrCH,
// the maximum value of the number of transport blocks Mi
// on each transport channel, and the maximum value of the
// number of DPDCHs P are given from the UE capability class."
// CHOICE(transport channel type)
// if Transport Channel Type == DCH
// Dynamic Transport Format Info: 1 to maxTF
// RLC Size integer(16..5000 by 8)
// TTI integer(10,20,40,80)
// (note: presence of TTY in dynamic info controlled by
// dynamic-TTI-usage opiton in semi-static transport format info
// Number of TBs integer(0..512)
// GSM25.212 says: Max number of TrCH in CCTrCH and max
// Logical channel List - logical channels allowed to use this RLC size.
// (Note, logical channels in list identified by RB id)
// Semi-static Transport Format Info see 103.5.11
// if Transport Channel Type == Common Transport channels
// much the same as above.
// 10.2.39 RRC Connection Request
// 10.2.40 RRC Connection Setup
// 10.2.33 RB Setup
// todo
// 10.3.4.21: RB Mapping Info
// todo
// RRC Connection Establishment Procedure 8.1.3
// RRC Connection Request includes IE "Domain Indicator" for PS or CS
// UTRAN returns RRC Connection Setup message.
// Primitives:
// TrCH id 10.3.5.18 integer(1..32)
// TFC integer(0..1023)
// 10.3.35a RRC State Indicator: enum(CELL_DCH,CELL_FACH,CELL_PCH,URA_PCH)
// indicates to a UE the RRC state to be entered.
// Default config for CELL_FACH 10.3.4.0a: Reserved for future versions of spec.
// RAB Identity 10.3.1.14 - string(8) identifies RAB to CN.
// No: This is used only for MAC-hs:
// MAC-d Flow Id 25.331 10.3.5.7b : integer(0..7) Used in 10.3.4.21 RB Mapping Info for MAC-hs only.
// RANAP GSM25.413:
// RANAP functions:
// Relocate serving RNC.
// Overall RAB management - set up, modify, release.
// Paging - provides CN capability to page UE
// and management of the Iu interface.
// From GSM 25.413 (RANAP): "The RAB ID shall uniquely identify the RAB
// for the specific CN domain and for the particular UE,
// which makes the RAB ID unique over the Iu connection on which
// the RAB ASSIGNMENT REQUEST message is received. When a
// RAB ID already in use over that particular Iu instance is used,
// the procedure is considered as modification of that RAB.
#endif