mirror of
				https://github.com/RangeNetworks/openbts.git
				synced 2025-10-31 11:53:33 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			264 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			264 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| * Copyright 2013, 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.
 | |
| 
 | |
| */
 | |
| 
 | |
| #ifndef _L3MMLAYER_H
 | |
| #define _L3MMLAYER_H 1
 | |
| 
 | |
| #include <Logger.h>
 | |
| #include <Interthread.h>
 | |
| #include <Timeval.h>
 | |
| 
 | |
| 
 | |
| #include <GSMTransfer.h>
 | |
| #include "ControlCommon.h"
 | |
| #include "PagingEntry.h"
 | |
| #include "L3TranEntry.h"		// Needed because InterthreadQueue deletes its elements on destruction.
 | |
| //#include "RadioResource.h"		// For Paging
 | |
| #include "L3Utils.h"
 | |
| #include <SIPDialog.h>
 | |
| 
 | |
| namespace Control {
 | |
| class MMLayer;
 | |
| class MMContext;
 | |
| typedef std::map<string,MMUser*> MMUserMap;
 | |
| using namespace GSM;
 | |
| 
 | |
| 
 | |
| #if 0
 | |
| // A list of pointers with methods designed for pointers that return NULL on error.
 | |
| template<class T>
 | |
| class PtrList : public std::list<T*> {
 | |
| 	//typedef typename std::list<T>::iterator itr_t;
 | |
| 	//typedef typename std::list<T> type_t;
 | |
| 	public:
 | |
| 	T* pop_front_ptr() {
 | |
| 		if (this->empty()) { return NULL; }
 | |
| 		T* result = this->front();
 | |
| 		this->pop_front();
 | |
| 		return result;
 | |
| 	}
 | |
| };
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 
 | |
| // This is the per-IMSI data for a subscriber, and a data-cache for data whose primary storage is persistent.
 | |
| // It is now persistent beyond the life of a single transaction call to save RRLP status.
 | |
| // Anything that needs to be persistent across reboots or shared via handover needs to be backed up
 | |
| // to the external TMSI table or to the external subscriber registry.
 | |
| // TODO: We should check the TMSI table when we create the MMUser
 | |
| DEFINE_MEMORY_LEAK_DETECTOR_CLASS(MMUser,MemCheckMMUser)
 | |
| class MMUser : public MemCheckMMUser /*: public RefCntBase*/ {
 | |
| 	// This is lock is to add/remove from the Transaction queues, since they are written from a thread in the SIP directory
 | |
| 	// and read from the thread running the LogicalChannel.
 | |
| 	friend class MMContext;
 | |
| 	mutable Mutex mmuLock;
 | |
| 	Timeval mmuPageTimer;
 | |
| 	protected:
 | |
| 	typedef PtrList<TranEntry> MMUQueue_t;
 | |
| 	MMUQueue_t mmuMTCq;
 | |
| 	MMUQueue_t mmuMTSMSq;
 | |
| 	friend class MMLayer;
 | |
| 	MMState mmuState;
 | |
| 	MMContext* mmuContext;
 | |
| 
 | |
| 	protected: string mmuImsi;		// Just the imsi, without "IMSI"
 | |
| 	public: 	string mmuGetImsi(bool verbose) { return mmuImsi.empty() ? (verbose ? "no-imsi" : "") : mmuImsi; }
 | |
| 
 | |
| 	protected:	TMSI_t mmuTmsi;
 | |
| 				Bool_z mmuDidTmsiCheck;	// Have we looked up the IMSI in the TMSI table yet?
 | |
| 	public: 	TMSI_t mmuGetTmsi();
 | |
| 
 | |
| 	protected:
 | |
| 	void mmuFree(MMUserMap::iterator *it,TermCause cause /*= TermCauseUnknown*/);	// This is the destructor.  It is not public.  Can only delete from gMMLayer because we must lock the universe first.
 | |
| 
 | |
| 	GSM::ChannelType mmuGetInitialChanType() const;
 | |
| 
 | |
| 	void MMUserInit() { mmuState = MMStateUndefined; mmuContext = NULL; }
 | |
| 	public:
 | |
| 	MMUser(string& wImsi);
 | |
| 	//MMUser(string& wImsi, TMSI_t wTmsi);
 | |
| 
 | |
| 	void mmuAddMT(TranEntry *tran);
 | |
| 	//void mmuPageReceived(L3LogicalChannel *chan);
 | |
| 	//void mmuClose();		// TODO
 | |
| 	bool mmuIsAttached() { return mmuContext != NULL; }	// Are we attached to a radio channel?
 | |
| 	bool mmuIsEmpty();
 | |
| 	void mmuCleanupDialogs();	// Let go of any dead dialogs
 | |
| 	//void mmuCallFinished(L3LogicalChannel *chan,MMCause cause);
 | |
| 	bool mmuServiceMTQueues();
 | |
| 	void mmuText(std::ostream&os) const;
 | |
| 	string mmuText() const;
 | |
| };
 | |
| std::ostream& operator<<(std::ostream& os, const MMUser&mmu);
 | |
| std::ostream& operator<<(std::ostream& os, const MMUser*mmu);
 | |
| 
 | |
| // This is the set of actively runnning TranEntrys on an L3LogicalChannel.
 | |
| // TODO: The MM operations should run directly on the MMContext, not in a TranEntry.
 | |
| DEFINE_MEMORY_LEAK_DETECTOR_CLASS(MMContext,MemCheckMMContext)
 | |
| class MMContext : public MemCheckMMContext /*: public RefCntBase*/ {
 | |
| 	friend class MMLayer;
 | |
| 	friend class MMUser;
 | |
| 	private:
 | |
| 	//mutable Mutex mmcLock;	// mostly unused
 | |
| 	int mmcChannelUseCnt;
 | |
| 	L3LogicalChannel *mmcChan;
 | |
| 	//RefCntPointer<MMUser> mmcMMU;
 | |
| 	MMUser* mmcMMU;
 | |
| 	//L3Timer TChReassignment;
 | |
| 
 | |
| 	void mmcMoveTransactions(MMContext *oldmmc);
 | |
| 	protected:
 | |
| 	void mmcUnlink();
 | |
| 	void mmcLink(MMUser *mmu);
 | |
| 	time_t mmcOpenTime;
 | |
| 
 | |
| 	// These are the Transactions/Procedures that may be active simultaneously:
 | |
| 	public:
 | |
| 	Bool_z mmcTerminationRequested;
 | |
| 	NeighborPenalty mmcHandoverPenalty;
 | |
| 	void chanSetHandoverPenalty(NeighborPenalty &wPenalty) { mmcHandoverPenalty = wPenalty; }
 | |
| 
 | |
| 
 | |
| 
 | |
| 	enum ActiveTranIndex {
 | |
| 		TE_first = 0,		// Start of table.
 | |
| 		TE_MM = 0,			// One MM Procedure.
 | |
| 		TE_CS1,			// Primary CS Transaction.
 | |
| 		TE_CSHold,		// CS transaction on hold.
 | |
| 		// Dont reorder these without checking for 'for' loops in L3MMLayer.cpp
 | |
| 		TE_MOSMS1,		// The primary MO-SMS.
 | |
| 		TE_MOSMS2,		// The follow-on MO-SMS.
 | |
| 		TE_MTSMS,		// Only one MT-SMS allowed at a time.
 | |
| 		TE_SS,			// Dedicated supplementary services transaction.
 | |
| 		TE_num			// Not a Transaction; The max number of entries in this table.
 | |
| 	};
 | |
| 	RefCntPointer<TranEntry> mmcTE[TE_num];
 | |
| 	unsigned mNextTI;
 | |
| 	InterthreadQueue<const L3Message> mmcServiceRequests;	// Incoming CM Service Request messages.
 | |
| 	void startSMSTran(TranEntry *tran);
 | |
| 
 | |
| 	void MMContextInit();
 | |
| 	void mmcFree(TermCause cause);	// This is the destructor.  It is not public.  Can only delete from gMMLayer because we must lock the MMUserMap first.
 | |
| 
 | |
| 	public:
 | |
| 	MMContext(L3LogicalChannel *chan);
 | |
| 	bool mmInMobilityManagement();	// Is a mobility management procedure running?
 | |
| 	//void mmClose();
 | |
| 	L3LogicalChannel *tsChannel() { return mmcChan; }
 | |
| 	MMContext *tsDup();
 | |
| 	void mmcPageReceived() const;
 | |
| 	time_t mmcDuration() const { return time(NULL) - mmcOpenTime; }
 | |
| 
 | |
| 	RefCntPointer<TranEntry> mmGetTran(unsigned ati) const;
 | |
| 	void mmConnectTran(ActiveTranIndex ati, TranEntry *tran);
 | |
| 	void mmConnectTran(TranEntry *tran);
 | |
| 	void mmDisconnectTran(TranEntry *tran);
 | |
| 
 | |
| 	unsigned mmGetNextTI();
 | |
| 	void getTranIds(TranEntryList &tranlist) const;
 | |
| 	// By returning a RefCntPointer we prevent destruction of the transaction during use by caller.
 | |
| 	RefCntPointer<TranEntry> tsGetVoiceTran() const { return mmcTE[TE_CS1]; }
 | |
| 	//void tsSetVoiceTran(TranEntry*tran) { mmcTE[TE_CS1] = tran; }
 | |
| 	void mmSetChannel(L3LogicalChannel *wChan) { mmcChan = wChan; }
 | |
| 	string mmGetImsi(bool verbose);		// If the IMSI is known, return it, else ""
 | |
| 
 | |
| 	bool mmIsEmpty();
 | |
| 	bool mmCheckNewActivity();	// Check for new activity.  Return true if any found. Also checks for normal channel release.
 | |
| 	bool mmCheckSipMsgs();		// Return true if anything happened.
 | |
| 	bool mmCheckTimers();		// Return true if anything happened.
 | |
| 	RefCntPointer<TranEntry> findTran(const L3Frame *frame, const L3Message *l3msg) const;
 | |
| 	bool mmDispatchL3Frame(const L3Frame *frame, const L3Message *msg);
 | |
| 	void l3sendm(const GSM::L3Message& msg, const GSM::Primitive& prim=GSM::L3_DATA, SAPI_t SAPI=SAPI0);
 | |
| 	void mmcText(std::ostream&os) const;
 | |
| };
 | |
| std::ostream& operator<<(std::ostream& os, const MMContext&mmc);
 | |
| std::ostream& operator<<(std::ostream& os, const MMContext*mmc);
 | |
| 
 | |
| // Maps imsi to MMUser.  No imsi, no MMUser.
 | |
| 
 | |
| extern Mutex gMMLock;
 | |
| class MMLayer {
 | |
| 	friend class MMUser;
 | |
| 	// Locking rules:
 | |
| 	// The thread running the L3LogicalChannel service loop "owns" the MMContext on its channel,
 | |
| 	// so it is allowed to manipulate it without locking this global Mutex.
 | |
| 	// Once the MMUser is 'attached' it cannot be deleted except by the the L3LogicalChannel thread,
 | |
| 	// so the MMUser can also be used by that thread without fear of destruction during use.
 | |
| 	// But MMUsers are created by an external thread (specifically, from SIPInterface) and may
 | |
| 	// be destroyed as a result of expired pages, so this global Mutex is used to 
 | |
| 	// to add/remove MMUsers, to search for MMUsers, paging,
 | |
| 	// to connect/disconnect an MMUser with/from a MMContext.
 | |
| 	// It is also used to create/delete MMContexts which is probably unnecessary.
 | |
| 	// The MMUser::Mutex is used only to protect the queues inside MMUser,
 | |
| 	// used to add/remove transactions to those queues.
 | |
| 	//Mutex gMMLock;
 | |
| 	Signal mmPageSignal;						///< signal to wake the paging loop
 | |
| 	MMUserMap MMUsers;
 | |
| 	public:
 | |
| 	void mmGetPages(NewPagingList_t &pages);
 | |
| 	void printPages(std::ostream &os);
 | |
| 	bool mmPageReceived(MMContext *mmchan, L3MobileIdentity &mobileId);
 | |
| 	// Add a new MT transaction, and signal the pager to come notice it.
 | |
| 	void mmAddMT(TranEntry *tran);
 | |
| 	void mmFreeContext(MMContext *mmc,TermCause cause);
 | |
| 	// This is called when the MT SIP engine on the other side has sent us another message.
 | |
| 	// (pat) We could be blocked for several reasons, including paging, waiting for LUR to complete, waiting for channel to change, etc.
 | |
| 	// But if we are paging, reset the paging timer so we keep paging.
 | |
| 	void mmMTRepage(const string imsi);	// Reset the paging timer so we continue paging.
 | |
| 	void mmAttachByImsi(L3LogicalChannel *chan, string imsi);
 | |
| 	bool mmTerminateByImsi(string imsi);
 | |
| 	//bool mmStartMTDialog(SIP::SipDialog*dialog, SIP::SipMessage*invite);
 | |
| 	MMUser *mmFindByImsi(string imsi, bool create=false);
 | |
| 	MMUser *mmFindByTmsi(uint32_t tmsi);
 | |
| 	MMUser *mmFindByMobileId(L3MobileIdentity&mid);
 | |
| 	void printMMUsers(std::ostream&os, bool onlyUnattached);
 | |
| 	void printMMInfo(std::ostream&os);
 | |
| 	string mmGetNeighborTextByImsi(string imsi, bool full);
 | |
| 	string printMMInfo();
 | |
| 
 | |
| 	// Is the single MTC slot busy?
 | |
| 	bool mmIsBusy(string &imsi) {
 | |
| 		ScopedLock lock(gMMLock,__FILE__,__LINE__);
 | |
| 		MMUser *mmu = mmFindByImsi(imsi,false);
 | |
| 		LOG(DEBUG) <<LOGVAR(imsi)<<LOGVAR(mmu);
 | |
| 		if (!mmu) return false;
 | |
| 		if (mmu->mmuMTCq.size()) return true;	// Someone already waiting in the MTC queue.
 | |
| 		if (!mmu->mmuContext) return false;
 | |
| 		LOG(DEBUG) <<"mmc="<<mmu->mmuContext;
 | |
| 		return mmu->mmuContext->tsGetVoiceTran() != NULL;
 | |
| 	}
 | |
| 
 | |
| 	RefCntPointer<TranEntry> mmFindVoiceTranByImsi(string &imsi) {
 | |
| 		ScopedLock lock(gMMLock,__FILE__,__LINE__);
 | |
| 		LOG(DEBUG);
 | |
| 		MMUser *mmu = mmFindByImsi(imsi,false);
 | |
| 		LOG(DEBUG) <<mmu;
 | |
| 		if (!mmu) return NULL;
 | |
| 		MMContext *mmc = mmu->mmuContext;
 | |
| 		LOG(DEBUG) <<mmc;
 | |
| 		if (!mmc) return NULL;
 | |
| 		LOG(DEBUG) << mmc->tsGetVoiceTran().self();
 | |
| 		return mmc->tsGetVoiceTran();
 | |
| 	}
 | |
| };
 | |
| 
 | |
| extern MMLayer gMMLayer;
 | |
| 
 | |
| };	// namespace Control
 | |
| 
 | |
| #endif
 |