/* * 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. */ #ifndef MSINFO_H #define MSINFO_H #include //#include #include "GPRSInternal.h" #include "GPRSRLC.h" //#include "RLCHdr.h" #include "RList.h" //#include "BSSG.h" #include "Utils.h" #include "SgsnExport.h" #define CASENAME(x) case x: return #x; namespace GSM { struct RadData; } namespace GPRS { typedef RList PDCHL1DownlinkList_t; typedef RList PDCHL1UplinkList_t; typedef RList TBFList_t; // A way to describe a collection of tbf states. // See TBF.h isActive() and isTransmitting(). enum TbfMacroState { TbfMAny, // any state TbfMActive, // any active state TbfMTransmitting // any transmitting state. }; // This should be in TBF.h but classes TBF and MSInfo are circularly referential. enum TbfCancelMode { TbfRetryInapplicable, // Tbf retry is inapplicable to an uplink tbf. TbfNoRetry, // Kill the tbf forever TbfRetryAfterRelease, // Retry tbf after sending a TbfRelease message. // If the tbf release message fails, fall back to RetryAfterTimeout. TbfRetryAfterWait // Retry tbf after timeout. }; enum MultislotSymmetry { MultislotSymmetric, // Use only symmetric multislot assignment, eg 2-down/2-up. MultislotFull // Use full multislot assignment, which may be assymetric. }; // GSM03.64 sec 6.2 // Note: The RROperatingMode is a state of the MS and known only at the layer2 MAC level. // The GSM spec says essentially that the RROperatingMode is simply whether // the MS thinks there is an active TBF running, which is not particularly useful to us. // What we need to track is whether the MS is listening to // CCCH (PacketIdle mode) or PDCH (PacketTransfer mode.) Generally when all TBFs are // finished the MS goes back to PacketIdle mode, but after a downlink transaction // we keep it camped on PDCH for a time determined by the T3192 timer, whose value // we broadcast in the System Information messages. // // Note: For T3192 timeout determination, dont forget to add the time delay // of the outgoing message queue, but that should be short. // But messages enqueued on CCCH may have long delays. // // This mode has almost nothing to do with Mobility Management Status, which is up in Layer3. // When the docs talk about "GPRS attached" they usually mean Mobility Mangement State, not this. // An MS in GMM state "Ready" (meaning the MS and SGSN have negotiated an SGSN supplied // TLLI for the MS instead of using the random TLLI the MS uses for its first uplink message) // will usually be in PacketIdle mode unless there is an ongoing TBF transaction. // For a non dual-transfer-mode MS, the MS must relinquish (or suspend) its GMM "Ready" state // to make a voice call, in which case it would no longer be in PacketIdle mode, // but that has almost no meaning at the MAC level. If the voice call ends and the MS wants // to use GPRS again, it will send us another RACH and we dont need to know that // a voice call was made in the meanwhile. class RROperatingMode { public: enum type { PacketIdle, PacketTransfer, //DualTransfer, // This mode was unnecessary: //Camped // This is our own mode, not an official RROperatingMode. // It marks the time MS is camped on Packet Channel between PacketTransfer // and PacketIdle, when the T3192 timer is running. // If a new transfer does not commence before T3192 expires, // MS is in PacketIdle mode. }; static const char *name(RROperatingMode::type mode); }; std::ostream& operator<<(std::ostream& os, const RROperatingMode::type &mode); // When we lose contact with the MS or something bad happens, we stop talking to it. // This says why. Reserve the first 100 numbers so the MsgTransactionType can be used // as a stop cause when the corresponding MsgTransactionType counter expires. class MSStopCause { public: enum type { AssignCounter = 1, // These were the values in release 3.0: //ShutDown = 2, //Stuck = 3, //Reassign = 4, // Reassignment failed. ShutDown = 102, Stuck = 103, //Reassign = 104, // Reassignment failed. Rach = 105, // Running TBF killed by a RACH. ReleaseCounter = 106, ReassignCounter = 107, NonResponsive = 108, // MS does not talk to us any more. Goof = 109, N3101 = 3101, N3103 = 3103, N3105 = 3105, T3191 = 3191, T3168 = 3168, CauseUnknown = 9999 // Used for unrecoverable internal inconsistency. }; //int mValue; //MSStopCause(/*enum MsgTransactionType*/ int wMsgTransType) : mValue(wMsgTransType) {} }; struct SignalQuality { // TODO: Get the Channel Quality Report from packet downlink ack/nack GSM04.60 11.2.6 Statistic msTimingError; Statistic msRSSI; // Dont bother saving RSSI as a float Statistic msChannelCoding; Statistic msCValue; Statistic msILevel; Statistic msRXQual; Statistic msSigVar; void setRadData(GSM::RadData &rd); void setRadData(float wRSSI,float wTimingError); void dumpSignalQuality(std::ostream &os) const; }; struct StatTotalHits { // Use ints instead of unsigned in case some statistic is buggy and runs backwards. Int_z mTotal; Int_z mGood; void clear() { mGood = mTotal = 0; } }; // keep the history of some success rate over the last few seconds for reporting purposes. class StatHits { // Keep totals for each of the last NumHist 48-block-multiframes, which is approx one second. public: static const int cNumHist = 20; private: StatTotalHits mTotal; // Totals for all time. StatTotalHits mHistory[cNumHist]; // Recent history. UInt_z mWhen[cNumHist]; // When the historical data in this history bucket was collected. // Return index in arrays above, which is the current 48-block-multiframe unsigned histind(); public: void addTotal() { mTotal.mTotal++; mHistory[histind()].mTotal++; } void addGood() { // increment only good count, not total. mTotal.mGood++; mHistory[histind()].mGood++; } void addMiss() { addTotal(); } void addHit() { // increment good and total. unsigned i = histind(); mTotal.mTotal++; mTotal.mGood++; mHistory[i].mTotal++; mHistory[i].mGood++; } void getStats(float *pER, int *pTotal, float *pWorstER, int *pWorstTotal); void textRecent(std::ostream &os); // Print the average for the last N seconds and worst second. void textTotal(std::ostream&os); // Print totals. }; // More MS statistics. Separate from MSInfo just because MSInfo is so large. struct MSStat { // This is a measure of the instantaneous traffic, used to pick the least busy channel. // It is incremented every time a block is sent/received, and decayed on a regular time schedule. UInt_z msTrafficMetric; StatHits msCountCcchReservations; StatHits msCountRbbpReservations; StatHits msCountBlocks; // Counts both uplink and downlink. UInt_z msConnectTime; void msAddConnectTime(unsigned msecs) { msConnectTime += msecs; } UInt_z msCountTbfs, msCountTbfFail, msCountTbfNoConnect; UInt_z msBytesUp, msBytesDown; //UInt_z msCountCcchReservations; //UInt_z msCountCcchReservationReplies; //UInt_z msCountRbbpReservations; //UInt_z msCountRbbpReservationReplies; //void service() { // // There are approx 48 blocks per second. // if (gBSNNext % 48 != 0) { return; } // unsigned ind = (gBSNNext / 48) % numHist; // msHistoryCcchReservations.sethits(int,msCountCcchReservations,msCountCcchReplies); // msHistoryRbbpReservations.sethits(int,msCountRbbpReservations,msCountRbbpReplies); // fivesecavg.countCcchReservations = msCountCcchReservations. //} // We use talkUp/talkDown to determine when the MS is non-responsive: GprsTimer msTalkUpTime; // When the MS last talked to us. GprsTimer msTalkDownTime; // When we last talked to the MS. // pat 3-2014: Use msDownlinkAttempts to detect that a high-side initiated downlink failed. UInt_z msDownlinkAttempts; // Called at every uplink/downlink communication from MS. // These are not strictly statistics because they are also used to kill a non-responsive MS. // These timers differ from the persistent mode timers in that those // count only data, and these count anything. // SVGDBG this means we are got something from the phone void talkedUp(bool doubleCount=false) { msDownlinkAttempts=0; msTalkUpTime.setNow(); if (!doubleCount) {msTrafficMetric++;} } void talkedDown() { msDownlinkAttempts=0; msTalkDownTime.setNow(); msTrafficMetric++; } // Dump all except traffic metric. void msStatDump(const char *indent,std::ostream &os); }; // MS Info a.k.a. Radio Context. There is one of these for each TLLI (not per-MS, per-TLLI) // GSM04.08 4.7.1.4 talks about GPRS attach, P-TMSI, and TLLI. // An MS, for our purposes in L2, is defined by its TLLI. No TLLI, no MSInfo struct. // The TLLI identifies the MS in all transactions except the initial RACH. // The RACH creates an anonymous packet uplink assignment for the MS, still identified // only by the RACH time, to transmit one block, which will be a Packet Resource Request // containing the all important TLLI. However, knowing the TLLI does not identify // a unique MS; the MS may (and usually does) use several of them. // Note that the MS can pick a "random" TLLI for itself when it does its first // GPRS-attach, but the SGSN issues a new "local" TLLI based on P-TMSI on AttachAccept. // The TLLI is specific to the sgsn, so if you switched sgsns, you would have a new TLLI, // however, the MS remembers its old TLLIs and will try calling in with them, // converted to foreign TLLIs. // // The spec is entirely botched up about whether the critical information needed // to communicate with the MS is in L3 (the SGSN) or L2 (the BTS.) // The SGSN stores the MS capabilities (RACap and DRX mode), which is ok but unnecessary, // since the MS retransmits them in every RAUpdate. // (The SGSN copies would be forwarded to the new cell during a cell change though.) // The problem is that we need to remember the radio parameters for the MS // (RSSI and TimingError), and a whole bunch of ad-hoc timers running in the MS // here in L2, where we identify MS using TLLI, // but the mapping of TLLI to MS (as known by IMSI) is in L3. Whoops! // Also note that during a TLLI reassignment procedure using BSSG, the SGSN commands // the BTS to switch TLLIs *after* it has received the Attach Complete Message, // which has already arrived [possibly but not always] using the new TLLI, // so here at L2 the MSInfo for the new TLLI already exists. // We are supposed to combine the two RadioContexts (MSInfos) when we get // the TLLI reassignment, and then recognize either TLLI. // The RSSI and TimingError are updated separately per-TLLI (ie, per-MSInfo struct) // because the MS initiates each conversation. // // The entire communication system between the MS and the SGSN can best // be described in terms of two different state-universes, corresponding // to the GPRS-Registration state: Registered (GPRS-Attached) or not. // In the pre-gprs-attach state the MS may call in with several TLLIs, // and we dont know how to correlate them to an actual MS. // In this case it is quite easy to lose communication with the MS, because // when an incoming RACH+PacketResourceRequest is answered, a new PACCH // may be assigned at random, and it may conflict with a previous assignment // that is on-going or in-flight on AGCH. // Also in this state I think there is simply no way to know for sure the state of the // per-MS timers, which are needed to know how to send the Immediate Assignment. // TODO: Maybe we should use a single PACCH timeslot for all unregistered TLLIs, // which implies communicationg the registration state from the SGSN to L2. // In the Registered-state we know that the new and old TLLI are the same physical MS, // and communication is more secure. We can assign a new PACCH for the MS. // By Registered we mean that both the SGSN and the MS agree on the // Registration state and the P-TMSI, which agreement is handshaked in both // directions (3 messages) and consumated by the AttachComplete message sent by MS to SGSN. #define TLLI_LOCAL_BIT 0x40000000 #define TLLI_MASK_LOCAL(tlli) ((tlli) & ~ TLLI_LOCAL_BIT) static __inline__ uint32_t tlliEq(uint32_t tlli1, uint32_t tlli2) { // Temporarily provide a way to disable this in case it does not work: if (gConfig.getBool("GPRS.LocalTLLI.Enable")) { return TLLI_MASK_LOCAL(tlli1) == TLLI_MASK_LOCAL(tlli2); } else { return tlli1 == tlli2; } } // vvv OLD COMMENT: // Formerly I changed the TLLI in the MSInfo struct to an oldTLLI on the command of the SGSN, // but that is incorrect - if the MS later sends another RACH using the oldTLLI, // we need to respond with that oldTLLI, not the newTLLI, although possibly we // should just ignore it in that case. // The RACH creates an anonymous packet uplink assignment for the MS, still identified // only by the RACH time, to transmit one block, which will be a Packet Resource Request // with a TLLI. If that TLLI maps to an old TLLI, it is because we have already // succeeded with the Attach Complete, and therefore it is safe to use the new TLLI. // Therefore, an MSInfo structure has one and only one TLLI, and the sole purpose of // TLLI is as a layer-2 transport identifier for the MS. // ^^^ OLD COMMENT // The MSInfo struct needs to hang around as long as the MS is in packet-transfer mode, // which means as long as it has TBFs, or the MS is in the T3192 period when it is camped // on the PACCH channel instead of the CCCH channel. // If we lose a connection with an MS, we keep the dead TBF around too until we // are sure it is no longer in use (config option, default 5 seconds), // so we dont need the MSInfo to survive after that. Doesn't hurt to keep it around, either. // An unused MSInfo eventually decays and is destroyed; this delay must be longer // than the expected use of the MSInfo by the SGSN - at least several seconds. // The SGSN is what remembers GPRS-attached MS, and will send us both a TLLI and the // MS capabilities (ie, multislot) in any transactions so that we can recreate the MSInfo at need. class MSInfo : public SGSN::MSUEAdapter, public SignalQuality, public MSStat { public: unsigned msDebugId; // Use of TLLI is in GSM04.08 4.7.1.5: P-TMSI handling. // From GSM03.03 sec 2.6: Structure of TLLI: // local TLLI is built by MS that has a valid P-TMSI: // top 2 bits 11, lower 30 bits are low 30 bits of P-TMSI. // foreign TLLI is built by an MS that has a valid P-TMSI from elswhere: // top 2 bits 10, lower 30 bits from P-TMSI; // random TLLI is built by an MS with no P-TMSI: // top top 5 bits 01111, lower 27 bits random. // auxiliary TLLI is built by SGSN: // top 5 bits 01110, lower 27 bits at SGSN discretion. // GSM03.03 sec 2.4: Structure of TMSI // The 32-bit TMSI has only local significance (within VLR or SGSN) and // is created at manufacturer discretion, however, for SGSN top // 2 bits must be 11, and it may not be all 1s, which value is reserved // to mean invalid. We also reserve value 0 to mean unset. // TMSI is stored in hex notation in 4 octets, and always ciphered. // GPRS-L2 doesn't care about any of the above, the SGSN knows those things. // In GPRS-L2 we just use whatever TLLI we are told. // An MSInfo structure is created as a result of an MS communication with a TLLI. // No TLLI, no MSInfo structure. These things can time out and die whenever // they want - their lifetime only needs to be as long as the RSSI and TimingError is valid. // They will be recreated if the MS RAChes us again. // In the spec they can also be created by a page from the SGSN, but not implemented here. // The MSInfo struct corresponds to an SgsnInfo in the SGSN, but because // either can be deleted any time we dont keep pointers between them, we always // look them up by TLLI for communication to/from the SGSN. // // This is as per the spec: // The msTlli is the TLLI we (the L2 layer) always use to communicate with the MS. // It is initialzied from the TLLI the MS used to communicate with us. // It is only changed if we get a 'change tlli' command from the SGSN, // which happens only after a successfully completed attach procedure, // (which is a fully acknowledged procedure with 3 way handshake) // at which time msTlli becomes msOldTlli, and we must subsequently recognize // either msTlli (the new sgsn-assigned one) or msOldTlli (the original one) // for uplink communication, but use only msTlli for downlink communication. // // This is not as per the spec: // After the attach is successful, we use only the assigned TLLI, // only one MSInfo structure, and everything is copascetic. // However, prior to a successful attach, I have seen the MS just use // several different TLLIs in uplink messages one right after the other, // maybe trying to find one that already works? // So many of these MSInfo refer to the same phone. // The spec deals with this by letting these things time out and die, // however, this results in conflicting in-flight assignments on AGCH // for different TLLIs that, in fact, refer to the same phone. // The spec does not provide any way for the L2 layer (us) to find that out. // So I introduced the AltTlli, which points to another MSInfo struct that // refers the same phone. It MUST NOT be used for communication with the MS, // however, it can be used to avoid launching conflicting assignments. // The Sgsn sends us AltTlli as the AliasTlli in the DownlinkQPdu. UInt32_z msTlli; // Identifies the MS, and is the TLLI used for downlink communication. UInt32_z msOldTlli; // Also identifies the MS, and must be recognized in uplink communication. UInt32_z msAltTlli; // Used to 'point' to another MSInfo struct that refers to the same MS, // as reported to us by the SGSN, which knows these things. // We save the TLLI instead of using a pointer because the other MSInfo // could disappear at any time. Bool_z msDeprecated; // This MS has been replaced by some other, which is another way // of saying that the active MS's oldTlli points to this one. // If the MS is in packet-idle state, there should be no TBFs. TBFList_t msTBFs; // TBFs for this MS, both uplink and downlink. #define RN_MS_FOR_ALL_TBF(ms,tbf) for (RListIterator itr(ms->msTBFs); itr.next(tbf); ) Int_z msUSFs[8]; // USF in each timeslot. // These are used by the RLCEngine to know when the MS has been granted a USF, ie, a chance to respond. Int_z msNumDataUSFGrants; // Total number of USF grants; reset when last TBF detached. Int_z msAckNackUSFGrant; // The msNumDataUSFGrants value of the last acknack. // Note: The uplink/downlink channels must all be in the same ARFCN that the MS is // camped on, and for multislot, follow strict timeslot adjacency rules. // The spec says that it is possible for different simultaneous TBFs for the same MS // to use different channel assignments, for exmaple, if the MS is sending a low-data-rate // TBF1 on a single channel and then wants to send a high-data-rate TBF2, it will interrupt // TBF2, may request a multislot allocation, and do TBF2 first. // Or another example, if TBF2 comes in and the TBF1 channel is on is congested, // the MAC can pick a different channel for TBF2. // However, we are not going to support that. The channels will be assigned to the MS // permanently, and all TBFs will use the same ones, which is why these lists are // here instead of in the TBF, where they really belong. // We may, however, someday change the channel assignments dynamically based on the // relative utilization of up and down links, for example, change from 4 down 1 up // to 4 up 1 down, etc., but if we do that we will have to wait until there are // no active TBFs, or reconfigure the existing TBFs. Having all the channels // here in the MSInfo instead of scattered in different TBFs will make // such reconfiguration easier. PDCHL1UplinkList_t msPCHUps; // uplink channels assigned to the MS; usually just one. PDCHL1DownlinkList_t msPCHDowns; // downlink channels assigned to the MS; usually just one. bool msCanUseUplinkTn(unsigned tn); bool msCanUseDownlinkTn(unsigned tn); // This is the channel the MS is listening to for messages. // It is set before the msPCH assignments above. // How did the MS come to be listening to this channel, you wonder? // When a RACH comes in to the BTS, we do not know what MS it belongs to, so we pick // the least busy GPRS channel and tell the MS to send its request on that channel. // From then on the MS listens to that channel until we tell it differently // in a channel assignment, which should be the next thing we send to it. // TODO: Is the below correct? Doesnt the MS always need to monitor PAACH which must // be one of its assigned channels? // It is possible for the msPCH assignments to not include the msPacch in several cases: // 1. If we deliberately give the MS a different channel assignment // for an uplink/downlink transfer, maybe because GPRS is underutilized and // we decided to close the channel. (Channel closing not implemented in first draft.) // 2. Maybe we decide on a different set of channels to satisfy this particular // MSs multislot requirements. // 3. If a previously attached MS starts a new RACH request, which will assign // a new PCH at random (because we dont know what MS it is yet) and for some // reason we havent cleared the msPCH channels, maybe because our timeouts are out of phase. // In this weird case a BSSG downlink command might try to talk to the MS on // the old channels, which might even possibly work if the new assignment and the // old happen to be the same. The special cases are complicated. // Note that if we used one-phase uplink access, this case 2 would extend in time out // into the uplink transfer, but we wont do that. PDCHL1FEC *msPacch; //RROperatingMode::type msMode; // Our belief about the state of MS: packet-idle, packet-transfer. UInt_z msIdleCounter; // Counts how long MS is without TBFs; eventually we delete it. UInt_z msStalled; // If MS is blocked, this is why, for error reporting. //Bool_z msUplinkRequest; // Request from phone to establish uplink was delayed due to existing uplink tbf. //RLCMsgChannelRequestDescriptionIE msUplinkRequestCRD; // The CRD for delayed request above. // GSM04.18 11.1.2: // T3141 - Started at Immediate Assignment, stopped when MS starts TBF. // We dont need it because we poll instead. // Note: Using Z100Timer is overkill for our single-threaded application; // could just use RLCBlockTime counters instead. // Counters and Timers defined in GSM04.60 sec 13. // We dont calculate N3105 and N3101 exactly the way the spec says, // but doesnt matter if they are off by 1 or 2. // NOTE: The blackberry sometimes waits 3 block periods before it starts // answering USFs, so N3101 better be bigger than that. UInt_z msN3101; // Number of unacknowledged USF grants (off by one.) // GSM04.60 sec 13: // Note: The MS may take advantage of this time period by keeping the TBF open // after a PDU finishes, and not sending anything for a long time, then // sending sending additional PDUs in the same TBF later, but before the timer expires. GSM::Z100Timer msT3191; // Waiting for acknowledgement of final TBF data block. // GSM04.60 sec 13: GSM::Z100Timer msT3193; // After downlink TBF finished, MS camps on PDCH this long. // MS runs same timer but called T3192. // GSM04.60 sec 13: GSM::Z100Timer msT3168; // MS camped on PDCH waiting for uplink assignment. // This timer is defined to be in the MS, not the BTS, // and we do not really need to track it as long as we // are sure we send the downlink assignment message // before this timer expires. The timer value is in // the sql and broadcast in the beacon. // However, I am using the timer as a way of tracking // whether the assignment is for a RACH, rather // than setting some other variable. // GSM04.60 sec 13: //GSM::Z100Timer msT3169; // Final timeout for dead tbf. //GSM::Z100Timer msT3195; // Final timeout for dead tbf. //GSM::Z100Timer msTxxxx; // Combined T3169, T3191, T3195 - timeout for // resource release after abnormal condition, during which time USF and TFI may not be reused. // When this MS was last granted a USF. // We use this when multiple MS are in contention for the uplink to make it fair. RLCBSN_t msLastUsfGrant; // Called when a USF is granted for this MS. // If penalize, if the MS does not answer we kill off the tbf. void msCountUSFGrant(bool penalize); // Incoming downlink data queue. // This queue is not between separate threads for BSSG, // and it is no longer for the internal sgsn either. //InterthreadQueue msDownlinkQueue; InterthreadQueue2 > msDownlinkQueue; Statistic msDownlinkQStat; Statistic msDownlinkQDelay; Timeval msDownlinkQOldest; // The timeval from the last guy in the queue. // Can this TBF use the specified uplink? bool canUseUplink(PDCHL1Uplink*up) { return msPCHUps.find(up); } // Can this TBF use the specified downlink? bool canUseDownlink(PDCHL1Downlink*down) { return msPCHDowns.find(down); } // Return the downlink channels as a bitmask for PacketDownlinkAssignment msg. unsigned char msGetDownlinkTimeslots(MultislotSymmetry sym); //PDCHL1Downlink *msPrimaryDownlink() { return msPCHDowns.front(); } bool msAssignChannels(); // Get channel(s) for this MS. private: bool msAddCh(unsigned chmask, const char *tnlist); bool msTrySlots(unsigned chmask,int down,int up); bool msAssignChannels2(int maxdown, int maxup, int sum); public: void msDeassignChannels(); // Release all channels for this MS. void msReassignChannels(); // Not implemented specially yet. //int msLastUplinkMsgBSN; // When did we last hear from this MS? MSInfo(uint32_t tlli); // Use msDelete instead of calling ~MSinfo() directly. void msDelete(bool forever=0); // If forever, do not move to expired list, just kill it. void msAddTBF(TBF *tbf) { devassert(! msTBFs.find(tbf)); msTBFs.push_back(tbf); } void msForgetTBF(TBF *tbf) { devassert(msTBFs.find(tbf)); msTBFs.remove(tbf); } // Called when a TBF goes dead. If it was the last active uplink TBF, surrender our USFs. void msCleanUSFs(); void msFailUSFs(); unsigned msGetDownlinkQueuedBytes(); //TBF * msGetDownlinkActiveTBF(); private: int msCountTBF1(RLCDirType dir, enum TbfMacroState tbfstate, TBF**ptbf=0) const; int msCountTBF2(RLCDirType dir, enum TbfMacroState tbfstate, TBF**ptbf=0); public: int msCountActiveTBF(RLCDirType dir, TBF**ptbf=0); int msCountTransmittingTBF(RLCDirType dir, TBF**ptbf=0); void msService(); void msStop(RLCDir::type dir, MSStopCause::type cause, TbfCancelMode cmode, int unsigned howlong); MSStopCause::type msStopCause; //void msRestart(); ChannelCodingType msGetChannelCoding(RLCDirType wdir) const; int msGetTA() const { return GetTimingAdvance(msTimingError.getCurrent()); } // All MS use the same power params at the moment. int msGetAlpha() const { return GetPowerAlpha(); } int msGetGamma() const { return GetPowerGamma(); } void msDump(std::ostream&os, SGSN::PrintOptions options); void msDumpCommon(std::ostream&os) const; void msDumpChannels(std::ostream&os) const; RROperatingMode::type getRROperatingMode(); string id() const; void msAliasTlli(uint32_t newTlli); void msChangeTlli(uint32_t newTlli); //void msSetUplinkRequest(RLCMsgChannelRequestDescriptionIE &wCRD) { // msUplinkRequest = true; // msUplinkRequestCRD = wCRD; //} // These are the functions required by the MSUEAdapter: uint32_t msGetHandle() { return msTlli; } string msid() const { return id(); } //void msWriteHighSide(ByteVector &dlpdu, uint32_t tlli, const char *descr) { //msDownlinkQueue.write(new GprsSgsnDownlinkPdu(dlpdu,tlli,descr)); //} void msDeactivateRabs(unsigned rabMask) {} // no-op in GPRS. bool msIsSuspended(); // Is the MS in suspended mode? bool msIsRegistered(); // Is the MS GPRS registered? bool isExtendedDynamic() { return msPCHUps.size() > msPCHDowns.size(); } bool msCanUseExtendedUplink(); }; extern unsigned gMSDebugId; std::ostream& operator<<(std::ostream& os, const MSInfo*ms); MSInfo *bssgMSChangeTLLI(unsigned oldTLLI,unsigned newTLLI); }; // namespace #endif