/**@file @brief Call Control messages, GSM 04.08 9.3 */ /* * Copyright 2008, 2009, 2014 Free Software Foundation, Inc. * Copyright 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. */ #define LOG_GROUP LogGroup::GSM // Can set Log.Level.GSM for debugging #include "GSML3CCElements.h" #include #include #define CASENAME(x) case x: return #x; using namespace std; using namespace Control; namespace GSM { void L3BearerCapability::writeV( L3Frame &dest, size_t &wp ) const { // See GSM 10.5.4.5. // This is a hell of a complex element, inherited from ISDN. // But we're going to ignore a lot of it. // "octet 3" dest.writeField(wp, mOctet3, 8); // zero or more "octet 3a" for (unsigned i = 0; i < mNumOctet3a; i++) { dest.writeField(wp,mOctet3a[i],8); } } void L3BearerCapability::parseV( const L3Frame& src, size_t &rp, size_t expectedLength ) { mPresent = true; // See GSM 10.5.4.5. // This is a hell of a complex element, inherited from ISDN. // (pat) If the bearer capability is not for speech, we dont save it. // Bits 1-3 of octet3 == 0 are the indicator, but the caller already lopped off the IEI and length // so it is in the first byte. if (expectedLength == 0) {return;} // Bad IE. Toss it. size_t end = rp + 8*expectedLength; unsigned octet3 = src.readField(rp,8); LOG(DEBUG) "BearerCapability"<= 3) { int sysid = src.readField(rp,8); int bitmapLength = src.readField(rp,8); // (pat) If there are two bytes, the second is the high bits, so we cant just // read them as a single field, we have to byte swap them. int fixedLength = min((int)expectedLength-2,bitmapLength); // Correct for error: bitmaplength longer than IE length. unsigned codeclist = 0; if (fixedLength >= 1) codeclist = src.readField(rp,8); if (fixedLength >= 2) codeclist |= (src.readField(rp,8) << 8); switch (sysid) { case SysIdGSM: mGsmPresent = true; mGsmCodecs.mCodecs = (CodecType)codeclist; break; case SysIdUMTS: mUmtsPresent = true; mUmtsCodecs.mCodecs = (CodecType)codeclist; break; default: // toss it. break; } expectedLength -= 2 + bitmapLength; } } // Return the CodecSet for the radio access technology that is currently in use, ie, // if OpenBTS product return gsm, if OpenNodeB product return umts. CodecSet L3SupportedCodecList::getCodecSet() const { #if RN_UMTS return mUmtsPresent ? mUmtsCodecs : CodecSet(); #else return mGsmPresent ? mGsmCodecs : CodecSet(); #endif } void L3SupportedCodecList::text(std::ostream& os) const { os << "SupportedCodecList=("; if (mGsmPresent) { os << "gsm="; mGsmCodecs.text(os); } if (mUmtsPresent) { if (mGsmPresent) {os<<",";} os << "umts="; mUmtsCodecs.text(os); } os << ")"; } Control::CodecSet L3CCCapabilities::getCodecSet() const { // (pat) I'm going to return an OR of all the codecs we find anywhere. Control::CodecSet result; if (mBearerCapability.mPresent) { result.orSet(mBearerCapability.getCodecSet()); } // This is supposedly only for UMTS but phones (Samsung Galaxy) may return it for GSM: if (mSupportedCodecs.mPresent) { result.orSet(mSupportedCodecs.getCodecSet()); } // If the phone doesnt report any capabilities, fall back to GSM_FR and hope. if (result.isEmpty()) { result.orType(GSM_FR); } return result; } void L3BCDDigits::parse(const L3Frame& src, size_t &rp, size_t numOctets, bool international) { unsigned i=0; size_t readOctets = 0; LOG(DEBUG) << "parse international " << international; if (international) mDigits[i++] = '+'; while (readOctets < numOctets) { unsigned d2 = src.readField(rp,4); unsigned d1 = src.readField(rp,4); readOctets++; mDigits[i++] = d1 == 10 ? '*' : d1 == 11 ? '#' : d1+'0'; if (d2!=0x0f) mDigits[i++] = d2 == 10 ? '*' : d2 == 11 ? '#' : d2+'0'; if (i>maxDigits) L3_READ_ERROR; } mDigits[i++]='\0'; } static int encode(char c, bool *invalid) { //return c == '*' ? 10 : c == '#' ? 11 : c-'0'; if (c == '*') return 10; if (c == '#') return 11; if (isdigit(c)) return c - '0'; *invalid = true; return 0; // Not sure what to do. } /* * If digit string starts with a plus strip off the plus. I suspect that this get encoded as an international type somewhere else * The write function send digits/information and the parse function decodes and store digits/incomming information. SVG */ void L3BCDDigits::write(L3Frame& dest, size_t &wp) const { bool invalid = false; unsigned index = 0; unsigned numDigits = strlen(mDigits); if (index < numDigits && mDigits[index] == '+') { LOG(DEBUG) << "write got +"; index++; } while (index < numDigits) { if ((index+1) < numDigits) dest.writeField(wp,encode(mDigits[index+1],&invalid),4); else dest.writeField(wp,0x0f,4); dest.writeField(wp,encode(mDigits[index],&invalid),4); index += 2; } if (invalid) { LOG(ERR) << "Invalid BCD string: '" <