/* * Copyright 2014, Range Networks, Inc. * 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. * 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. */ #define LOG_GROUP LogGroup::GSM // Can set Log.Level.GSM for debugging #include "GSMRadioResource.h" #include "GSMCommon.h" #include "GSMConfig.h" #include "GSMLogicalChannel.h" #include "GSMCCCH.h" #include #include // For L3TranEntryId, NewTransactionTable. #include namespace GSM { using namespace Control; /** Determine the channel type needed. GSM 04.08 9.1.8, Table 9.3 and 9.3a. Assumes we do not support call reestablishment. @param RA The request reference from the channel request message. @return channel type code, undefined if not a supported service */ ChannelType decodeChannelNeeded(unsigned RA) { // This code is based on GSM 04.08 Table 9.9. section 9.1.8 unsigned RA4 = RA>>4; unsigned RA5 = RA>>5; // We use VEA for all emergency calls, regardless of configuration. if (RA5 == 0x05) return TCHFType; // emergency call // Answer to paging, Table 9.9a. // We don't support TCH/H, so it's wither SDCCH or TCH/F. // The spec allows for "SDCCH-only" MS. We won't support that here. // FIXME -- So we probably should not use "any channel" in the paging indications. if (RA5 == 0x04) return TCHFType; // any channel or any TCH. if (RA4 == 0x01) return SDCCHType; // SDCCH if (RA4 == 0x02) return TCHFType; // TCH/F if (RA4 == 0x03) return TCHFType; // TCH/F if ((RA&0xf8) == 0x78 && RA != 0x7f) return PSingleBlock1PhaseType; if ((RA&0xf8) == 0x70) return PSingleBlock2PhaseType; int NECI = gConfig.getNum("GSM.CellSelection.NECI"); if (NECI==0) { if (RA5 == 0x07) return SDCCHType; // MOC or SDCCH procedures if (RA5 == 0x00) return SDCCHType; // location updating } else { if (gConfig.getBool("Control.VEA")) { // Very Early Assignment if (RA5 == 0x07) return TCHFType; // MOC for TCH/F if (RA4 == 0x04) return TCHFType; // MOC, TCH/H sufficient } else { // Early Assignment if (RA5 == 0x07) return SDCCHType; // MOC for TCH/F if (RA4 == 0x04) return SDCCHType; // MOC, TCH/H sufficient } if (RA4 == 0x00) return SDCCHType; // location updating if (RA4 == 0x01) return SDCCHType; // other procedures on SDCCH } // Anything else falls through to here. // We are still ignoring data calls, LMU. return UndefinedCHType; } /** Return true if RA indicates LUR. */ bool requestingLUR(unsigned RA) { int NECI = gConfig.getNum("GSM.CellSelection.NECI"); if (NECI==0) return ((RA>>5) == 0x00); else return ((RA>>4) == 0x00); } // Return a RACH channel request message (what we call RA) for various types of channel requests. // The RA is only 8 bits. static unsigned createFakeRachRA(FakeRachType rachtype) { switch (rachtype) { default: devassert(0); case FakeRachTCH: return 0xe0 | (0x1f & random()); // top 3 bits are 0x7. case FakeRachSDCCH: return 0x10 | (0x0f & random()); // top 4 bits are 0001 case FakeRachLUR: return 0x00 | (0x0f & random()); // top 4 bits are 0000 case FakeRachGPRS: return 0x70 | (0x7 & random()); // top 5 bits are 01110. case FakeRachAnswerToPaging: return 0x80 | (0x1f & random()); // top 3 bits are 100. } } FakeRachType fakeRachTypeTranslate(const char *name) { if (strcasestr(name,"tch")) return FakeRachTCH; if (strcasestr(name,"sdcch")) return FakeRachSDCCH; if (strcasestr(name,"lur")) return FakeRachLUR; if (strcasestr(name,"gprs")) return FakeRachGPRS; if (strcasestr(name,"pag")) return FakeRachAnswerToPaging; LOG(ERR) <<"Unrecognized fake rach type: " <MaxTA) { RachInfo tmpRACH(RA,when,RadData(RSSI,timingError)); // Temporary just so we can print it more easily. LOG(NOTICE) << "ignoring RACH burst TE > "<62) initialTA=62; RachInfo *rip = new RachInfo(RA,when,RadData(RSSI,initialTA),TN); LOG(DEBUG) << "Incoming RACH:" <<*rip <mWhen.FN() % 42432); enqueueRach(rip); } };