diff --git a/public-trunk/CLI/CLI.cpp b/public-trunk/CLI/CLI.cpp index 19fba44..4ecc06b 100644 --- a/public-trunk/CLI/CLI.cpp +++ b/public-trunk/CLI/CLI.cpp @@ -363,7 +363,17 @@ int sendrrlp(int argc, char** argv, ostream& os, istream& is) return SUCCESS; } - +/** Send USSD to an IMSI. */ +int sendUSSD(int argc, char** argv, ostream& os, istream& is) +{ + if (argc!=2) return BAD_NUM_ARGS; + char *IMSI = argv[1]; + GSM::L3MobileIdentity mobileIdentity(IMSI); + Control::MTTestHandler handler(mobileIdentity, (unsigned)1, (unsigned)0, Control::USSDData::REGrequest, std::string("REGrequest")); + handler.run(); + os << "MT USSD session end." << endl; + return SUCCESS; +} /** Print current usage loads. */ int printStats(int argc, char** argv, ostream& os, istream& is) @@ -762,6 +772,7 @@ Parser::Parser() addCommand("findimsi", findimsi, "[IMSIPrefix] -- prints all imsi's that are prefixed by IMSIPrefix"); addCommand("sendsms", sendsms, " -- send SMS to , addressed from , after prompting."); addCommand("sendrrlp", sendrrlp, " -- send RRLP message to ."); + addCommand("sendussd", sendUSSD, " -- send USSD to "); addCommand("load", printStats, "-- print the current activity loads."); addCommand("cellid", cellID, "[MCC MNC LAC CI] -- get/set location area identity (MCC, MNC, LAC) and cell ID (CI)"); addCommand("calls", calls, "-- print the transaction table"); diff --git a/public-trunk/CommonLibs/Threads.cpp b/public-trunk/CommonLibs/Threads.cpp index df2e3a1..2628ab1 100644 --- a/public-trunk/CommonLibs/Threads.cpp +++ b/public-trunk/CommonLibs/Threads.cpp @@ -95,6 +95,15 @@ void Signal::wait(Mutex& wMutex, unsigned timeout) const pthread_cond_timedwait(&mSignal,&wMutex.mMutex,&waitTime); } +/** Wait for semaphore to be signaled with timeout. +* @returns 0 on success, -1 on error or timeout. +*/ +int ThreadSemaphore::wait(unsigned timeout) const +{ + Timeval then(timeout); + struct timespec waitTime = then.timespec(); + return sem_timedwait(&mSem,&waitTime); +} void Thread::start(void *(*task)(void*), void *arg) { diff --git a/public-trunk/CommonLibs/Threads.h b/public-trunk/CommonLibs/Threads.h index 0f12972..1b0d962 100644 --- a/public-trunk/CommonLibs/Threads.h +++ b/public-trunk/CommonLibs/Threads.h @@ -29,6 +29,7 @@ #include #include #include +#include class Mutex; @@ -120,7 +121,37 @@ class Signal { }; +/** Semaphore */ +class ThreadSemaphore { + private: + + mutable sem_t mSem; + + public: + + ThreadSemaphore(int pshared = 0, unsigned value = 0) { assert(sem_init(&mSem,pshared,value)!=-1); } + + ~ThreadSemaphore() { sem_destroy(&mSem); } + + /** Wait for semaphore to be signaled with timeout. + * @returns 0 on success, -1 on error or timeout. + */ + int wait (unsigned timeout) const; + + /** Wait for semaphore to be signaled infinitely. + * @returns 0 on success, -1 on error. + */ + int wait() const { return sem_wait(&mSem); } + + /** Check if semaphore has been signaled and disarm it. + * @returns 0 if semaphore has been signaled, -1 in other cases. + */ + int trywait() const { return sem_trywait(&mSem); } + + int post() { return sem_post (&mSem); } + +}; #define START_THREAD(thread,function,argument) \ thread.start((void *(*)(void*))function, (void*)argument); diff --git a/public-trunk/Control/ControlCommon.cpp b/public-trunk/Control/ControlCommon.cpp index 9f92f53..609f16b 100644 --- a/public-trunk/Control/ControlCommon.cpp +++ b/public-trunk/Control/ControlCommon.cpp @@ -51,8 +51,26 @@ TransactionTable gTransactionTable; TMSITable gTMSITable; +ostream& Control::operator<<(ostream& os, USSDData::USSDMessageType type) +{ + switch (type) { + case USSDData::REGrequest: os << "register request"; break; + case USSDData::request: os << "request"; break; + case USSDData::notify: os << "notify"; break; + case USSDData::response: os << "response"; break; + case USSDData::error: os << "error"; break; + case USSDData::release: os << "release"; break; + default: os << "?" << (int)type << "?"; + } + return os; +} - +ostream& Control::operator<<(ostream& os, const USSDData& data) +{ + os << "USSD message type: " << data.MessageType(); + os << "USSD string: " << data.USSDString(); + return os; +} TransactionEntry::TransactionEntry() :mID(gTransactionTable.newID()), @@ -123,6 +141,24 @@ TransactionEntry::TransactionEntry(const L3MobileIdentity& wSubscriber, mMessage[0]='\0'; } +/** This form is used for USSD. */ +TransactionEntry::TransactionEntry(const GSM::L3MobileIdentity& wSubscriber, + const GSM::L3CMServiceType& wService, + unsigned wTIFlag, + unsigned wTIValue, + USSDData* wUSSDData) + :mID(gTransactionTable.newID()), + mSubscriber(wSubscriber),mService(wService), + mTIFlag(wTIFlag),mTIValue(wTIValue),mUSSDData(wUSSDData), + mQ931State(NullState), + mT301(T301ms), mT302(T302ms), mT303(T303ms), + mT304(T304ms), mT305(T305ms), mT308(T308ms), + mT310(T310ms), mT313(T313ms), + mT3113(gConfig.getNum("GSM.T3113")), + mTR1M(GSM::TR1Mms) +{ + mMessage[0]='\0'; +} bool TransactionEntry::timerExpired() const @@ -207,6 +243,8 @@ ostream& Control::operator<<(ostream& os, TransactionEntry::Q931CallState state) case TransactionEntry::ReleaseRequest: os << "release request"; break; case TransactionEntry::SMSDelivering: os << "SMS delivery"; break; case TransactionEntry::SMSSubmitting: os << "SMS submission"; break; + case TransactionEntry::USSDworking: os << "USSD working"; break; + case TransactionEntry::USSDclosing: os << "USSD closing"; break; default: os << "?" << (int)state << "?"; } return os; @@ -572,7 +610,270 @@ void TMSITable::load(const char* filename) fclose(fp); } +unsigned USSDHandler::waitUSSDData(Control::USSDData::USSDMessageType* messageType, std::string* USSDString, unsigned timeout = USSDHandler::infinitely) +{ + TransactionEntry transaction; + // Wait for MS to signal that data is ready + gTransactionTable.find(mTransactionID, transaction); + + if (timeout >= USSDHandler::infinitely) + { + if (transaction.ussdData()->waitMS()!=0) + { + LOG(ERROR) << "USSDDate semaphore returned error: " << errno; + return 2; + } + } + else if((timeout > USSDHandler::trywait) && (timeout < USSDHandler::infinitely)) + { + //wait + if (transaction.ussdData()->waitMS(timeout)!=0) + { + LOG(DEBUG) << "USSDDate semaphore returned error or timeout"; + return 2; + } + } + else + { + //trywait + if (transaction.ussdData()->trywaitMS()!=0) + { + LOG(DEBUG) << "USSDDate semaphore returned error"; + return 2; + } + } + // Get data from MS and check for closing condition + gTransactionTable.find(mTransactionID, transaction); + if (transaction.Q931State() == Control::TransactionEntry::USSDclosing) + { + clearTransactionHistory(transaction); + LOG(DEBUG) << "USSD clearing...."; + return 1; + } + *messageType = transaction.ussdData()->MessageType(); + *USSDString = transaction.ussdData()->USSDString(); + return 0; +} + +void USSDHandler::postUSSDData(Control::USSDData::USSDMessageType messageType, std::string USSDString) +{ + if (USSDString.length()>183) + { + mString = USSDString; + mString.erase(mString.begin(), mString.begin()+181); + USSDString.erase(USSDString.begin()+181, USSDString.end()); + USSDString+=">"; + } + else mString = ""; + TransactionEntry transaction; + gTransactionTable.find(mTransactionID, transaction); + transaction.ussdData()->MessageType(messageType); + transaction.ussdData()->USSDString(USSDString); + gTransactionTable.update(transaction); + transaction.ussdData()->postNW(); +} + +void *USSDHandler::runWrapper(void *pThis) +{ + ((USSDHandler*)pThis)->run(); + return NULL; +} + +void MOTestHandler::run() +{ + LOG(DEBUG) << "USSD MO Test Handler RUN"; + while(true) + { + Control::USSDData::USSDMessageType messageType; + std::string USSDString; + if (waitUSSDData(&messageType, &USSDString, gConfig.getNum("USSD.timeout"))) break; + if (USSDString == ">") + { + if (mString == "") + { + messageType = USSDData::release; + } + else + { + USSDString = mString; + messageType = USSDData::request; + } + } + else if (USSDString == "*100#") + { + USSDString = "handle response "; + messageType = USSDData::response; + } + else if(USSDString == "*101#") + { + USSDString = "handle request String objects are a special type of container, specifically designed to operate with sequences of characters. Unlike traditional c-strings, which are mere sequences of characters in a memory array, C++ string objects belong to a class with many built-in features to operate with strings in a more intuitive way and with some additional useful features common to C++ containers. The string class is an instantiation of the basic_string class template, defined in string as:"; + messageType = USSDData::request; + } + else if(USSDString == "*1011#") + { + USSDString = "handle request"; + messageType = USSDData::request; + } + else if(USSDString == "*102#") + { + USSDString = "handle notify"; + messageType = USSDData::notify; + } + else if(USSDString == "*103#") + { + messageType = USSDData::release; + } + else if(USSDString == "*104#") + { + messageType = USSDData::error; + } + else + { + messageType = USSDData::release; + } + + postUSSDData(messageType, USSDString); + } +} + +void MOHttpHandler::run() +{ + LOG(DEBUG) << "USSD MO Http Handler RUN"; + while(true) + { + Control::USSDData::USSDMessageType messageType; + std::string USSDString; + if (waitUSSDData(&messageType, &USSDString, gConfig.getNum("USSD.timeout"))) break; + + if (USSDString == ">") + { + if (mString == "") + { + messageType = USSDData::release; + } + else + { + USSDString = mString; + messageType = USSDData::request; + } + } + else if(USSDString == "*101#") + { + USSDString = "send command"; + messageType = USSDData::request; + } + else + { + char command[2048]; + sprintf(command,"wget -T 5 -q -O - \"http://%s/http/%s&to=%s&text=%s\"", + gConfig.getStr("USSD.HTTP.Gateway"), + gConfig.getStr("USSD.HTTP.AccessString"), + "server", USSDString.c_str()); + LOG(NOTICE) << "MOUSSD: send HTTP sending with " << command; + // HTTP "GET" method with wget. + char mystring [182]; + FILE* wget = popen(command,"r"); + if (!wget) { + LOG(NOTICE) << "cannot open wget with " << command; + USSDString = "cannot open wget"; + messageType = USSDData::release; + } + fgets (mystring , 182 , wget); + LOG(NOTICE) << "wget response " << mystring; + std::string tmpStr(mystring); + USSDString = tmpStr; + messageType = USSDData::request; + } + postUSSDData(messageType, USSDString); + } +} + +void MOCLIHandler::run() +{ + LOG(DEBUG) << "USSD MO CLI Handler RUN"; + while(true) + { + Control::USSDData::USSDMessageType messageType; + std::string USSDString; + if (waitUSSDData(&messageType, &USSDString, gConfig.getNum("USSD.timeout"))) break; + + if (USSDString == ">") + { + if (mString == "") + { + messageType = USSDData::release; + } + else + { + USSDString = mString; + messageType = USSDData::request; + } + } + else if(USSDString == "*101#") + { + USSDString = "send command"; + messageType = USSDData::request; + } + else + { + const char* line; + line = USSDString.c_str(); + std::ostringstream os; + std::istringstream is; + gParser.process(line, os, is); + LOG(INFO) << "Running line \"" << line << "\" returned result \"" << os.str() << "\""; + USSDString = os.str(); + messageType = USSDData::request; + } + postUSSDData(messageType, USSDString); + } +} + +void MTTestHandler::run() +{ + LOG(DEBUG) << "USSD MT Test Handler RUN"; + while(true) + { + Control::USSDData::USSDMessageType messageType; + std::string USSDString; + if (waitUSSDData(&messageType, &USSDString, gConfig.getNum("USSD.timeout"))) break; + + if(messageType == USSDData::REGrequest) + { + USSDString = "REGrequest message"; + } + else if(messageType == USSDData::response) + { + if (USSDString == "111") + { + USSDString = "release message"; + messageType = USSDData::release; + } + else if (USSDString == "100") + { + USSDString = "request message"; + messageType = USSDData::request; + } + else if (USSDString == "101") + { + messageType = USSDData::error; + } + else if (USSDString == "102") + { + USSDString = "notify message"; + messageType = USSDData::notify; + } + } + else + { + USSDString = "release message"; + messageType = USSDData::release; + } + + postUSSDData(messageType, USSDString); + } +} bool Control::waitForPrimitive(LogicalChannel *LCH, Primitive primitive, unsigned timeout_ms) @@ -728,7 +1029,53 @@ void Control::resolveIMSI(L3MobileIdentity& mobileIdentity, LogicalChannel* LCH } } - +unsigned Control::USSDDispatcher(GSM::L3MobileIdentity &mobileIdentity, unsigned TIFlag, unsigned TIValue,Control::USSDData::USSDMessageType messageType, string ussdString, bool MO) +{ + TransactionEntry transaction(mobileIdentity, GSM::L3CMServiceType::SupplementaryService, TIFlag, TIValue, new USSDData(messageType)); + gTransactionTable.add(transaction); + LOG(DEBUG) << "USSD Dispatcher"; + transaction.ussdData()->USSDString(ussdString); + if (MO) + { + //MO + transaction.Q931State(Control::TransactionEntry::USSDworking); + transaction.ussdData()->postMS(); + gTransactionTable.update(transaction); + std::string handleName = gConfig.getStr("USSD.Handler.MO"); + Thread* thread = new Thread; + if (handleName=="HTTP") + { + MOHttpHandler* handler = new MOHttpHandler(transaction.ID()); + thread->start((void*(*)(void*))USSDHandler::runWrapper, handler); + } + else if (handleName=="CLI") + { + MOCLIHandler* handler = new MOCLIHandler(transaction.ID()); + thread->start((void*(*)(void*))USSDHandler::runWrapper, handler); + } + else if (handleName=="Test") + { + MOTestHandler* handler = new MOTestHandler(transaction.ID()); + thread->start((void*(*)(void*))USSDHandler::runWrapper, handler); + } + else + { + MOTestHandler* handler = new MOTestHandler(transaction.ID()); + thread->start((void*(*)(void*))USSDHandler::runWrapper, handler); + } + } + else + { + //MT + transaction.ussdData()->postNW(); + transaction.Q931State(Control::TransactionEntry::Paging); + //gTransactionTable.add(transaction); + gTransactionTable.update(transaction); + LOG(DEBUG) << "USSD Start Paging"; + gBTS.pager().addID(transaction.subscriber(),GSM::SDCCHType,transaction); + } + return transaction.ID(); +} // vim: ts=4 sw=4 diff --git a/public-trunk/Control/ControlCommon.h b/public-trunk/Control/ControlCommon.h index ff950b5..db22e99 100644 --- a/public-trunk/Control/ControlCommon.h +++ b/public-trunk/Control/ControlCommon.h @@ -145,7 +145,14 @@ void clearTransactionHistory(unsigned transactionID); //@} +/**@name USSD */ +//@{ +/** MO USSD controller */ +void MOUSSDController(const GSM::L3CMServiceRequest *req, GSM::LogicalChannel *LCH); +/** MTUSSD controller */ +void MTUSSDController(TransactionEntry& transaction, GSM::LogicalChannel *LCH); +//@} /**@name Functions for mobility manangement operations. */ //@{ @@ -208,6 +215,8 @@ void MTSMSController(TransactionEntry& transaction, GSM::LogicalChannel *LCH); //@} + + /** Create a new transaction entry and start paging. */ void initiateMTTransaction(TransactionEntry& transaction, GSM::ChannelType chanType, unsigned pageTime); @@ -242,7 +251,6 @@ void resolveIMSI(GSM::L3MobileIdentity& mobID, GSM::LogicalChannel* LCH); - /**@ Paging mechanisms */ //@{ @@ -365,8 +373,59 @@ void *PagerServiceLoopAdapter(Pager*); //@} // paging mech +/**@name USSD data */ +//@{ + +class USSDData { + + public: + /** USSD message types based on GSM 03.09 */ + enum USSDMessageType { + REGrequest, + request, + notify, + response, + error, + release + }; + + private: + + ThreadSemaphore mSemWaitMS; + ThreadSemaphore mSemWaitNW; + USSDMessageType mType; // USSD message type + std::string mUSSDString; // USSD message string + + public: + + USSDData(const USSDMessageType& wType) + :mType(wType) + {} + + void MessageType(USSDMessageType wType) { mType=wType; } + USSDMessageType MessageType() const { return mType; } + std::string USSDString() const { return mUSSDString; } + void USSDString(std::string wUSSDString) { mUSSDString = wUSSDString; } + + int waitMS() { return mSemWaitMS.wait(); } + int waitNW() { return mSemWaitNW.wait(); } + + int waitMS(unsigned timeout) { return mSemWaitMS.wait(timeout); } + int waitNW(unsigned timeout) { return mSemWaitNW.wait(timeout); } + + int trywaitMS() { return mSemWaitMS.trywait(); } + int trywaitNW() { return mSemWaitNW.trywait(); } + int postMS() { return mSemWaitMS.post(); } + int postNW() { return mSemWaitNW.post(); } + +}; + +std::ostream& operator<<(std::ostream& os, USSDData::USSDMessageType); +std::ostream& operator<<(std::ostream& os, const USSDData&); + +//@} /**@name Transaction Table mechanisms. */ //@{ @@ -395,6 +454,8 @@ class TransactionEntry { ReleaseRequest, SMSDelivering, SMSSubmitting, + USSDworking, + USSDclosing }; private: @@ -412,6 +473,8 @@ class TransactionEntry { Q931CallState mQ931State; ///< the GSM/ISDN/Q.931 call state Timeval mStateTimer; ///< timestamp of last state change. + USSDData* mUSSDData; ///< USSD message data + char mMessage[256]; ///< text messaging payload /**@name Timers from GSM and Q.931 (network side) */ @@ -452,6 +515,13 @@ class TransactionEntry { unsigned wTIValue, const GSM::L3CallingPartyBCDNumber& wCalling); + /** This form is used for USSD. */ + TransactionEntry(const GSM::L3MobileIdentity& wSubscriber, + const GSM::L3CMServiceType& wService, + unsigned wTIFlag, + unsigned wTIValue, + USSDData* wUSSDData); + /**@name Accessors. */ //@{ unsigned TIValue() const { return mTIValue; } @@ -488,6 +558,9 @@ class TransactionEntry { Q931CallState Q931State() const { return mQ931State; } + void ussdData(USSDData* wUSSDData) { mUSSDData=wUSSDData; } + USSDData* ussdData() const { return mUSSDData; } + unsigned stateAge() const { return mStateTimer.elapsed(); } /**@name Timer access. */ @@ -695,7 +768,7 @@ class TMSITable { /** Find an IMSI in the table. This is a log-time operation. - @param TMSI The TMSI to find. + @param TMSI The TMSI to find.post to @return Pointer to c-string IMSI or NULL. */ const char* IMSI(unsigned TMSI) const; @@ -783,9 +856,10 @@ class ControlLayerException { /** Thrown when the control layer gets the wrong message */ class UnexpectedMessage : public ControlLayerException { public: - UnexpectedMessage(unsigned wTransactionID=0) - :ControlLayerException(wTransactionID) + UnexpectedMessage(unsigned wTransactionID=0, const GSM::L3Frame *pFrame=NULL) + :ControlLayerException(wTransactionID), mpFrame(pFrame) {} + const GSM::L3Frame *mpFrame; }; /** Thrown when recvL3 returns NULL */ @@ -819,13 +893,7 @@ class Q931TimerExpired : public ControlLayerException { :ControlLayerException(wTransactionID) {} }; - - -//@} - - -} //Control - +} /**@addtogroup Globals */ @@ -837,6 +905,93 @@ extern Control::TMSITable gTMSITable; //@} +namespace Control { + +unsigned USSDDispatcher(GSM::L3MobileIdentity &mobileIdentity, unsigned TIFlag, unsigned TIValue, Control::USSDData::USSDMessageType messageType, std::string ussdString, bool MO); + + +class USSDHandler { + + public: + enum USSDtimeout { + trywait = 0, + infinitely = 120000 + }; + private: + unsigned mTransactionID; + + protected: + std::string mString; + + public: + /** This form is used for MO USSD */ + USSDHandler(unsigned wTransactionID) + :mTransactionID(wTransactionID), + mString("") + {} + /** This form is used for MT USSD */ + USSDHandler(GSM::L3MobileIdentity &mobileIdentity, unsigned TIFlag, unsigned TIValue, Control::USSDData::USSDMessageType messageType, std::string ussdString) + :mString("") + { + mTransactionID = USSDDispatcher(mobileIdentity, TIFlag, TIValue, messageType, ussdString, false); + } + /** Wait USSD data from MS. Return: 0 - successful, 1 - clear transaction, 2 - error or timeout */ + unsigned waitUSSDData(Control::USSDData::USSDMessageType* messageType, std::string* USSDString, unsigned timeout); + /** Post USSD data and update transaction with new USSDData (messageType and USSDString)*/ + void postUSSDData( Control::USSDData::USSDMessageType messageType, std::string USSDString); + unsigned transactionID() { return mTransactionID; } + void transactionID(unsigned wTransactionID) { wTransactionID = mTransactionID; } + static void *runWrapper(void *pThis); + + protected: + virtual void run() = 0; + +}; + + +class MOTestHandler : public USSDHandler { + public: + MOTestHandler(unsigned wTransactionID) + :USSDHandler(wTransactionID) + {} + void run(); +}; + +class MOHttpHandler : public USSDHandler { + public: + MOHttpHandler(unsigned wTransactionID) + :USSDHandler(wTransactionID) + {} + + void run(); +}; + +class MOCLIHandler : public USSDHandler { + public: + MOCLIHandler(unsigned wTransactionID) + :USSDHandler(wTransactionID) + {} + + void run(); +}; + +class MTTestHandler : public USSDHandler { + public: + MTTestHandler(GSM::L3MobileIdentity &mobileIdentity, unsigned TIFlag, unsigned TIValue, Control::USSDData::USSDMessageType messageType, std::string ussdString) + :USSDHandler(mobileIdentity,TIFlag, TIValue, messageType, ussdString) + {} + + void run(); +}; + +//@} + + +} //Control + + + + #endif diff --git a/public-trunk/Control/DCCHDispatch.cpp b/public-trunk/Control/DCCHDispatch.cpp index 2d893b8..94b4122 100644 --- a/public-trunk/Control/DCCHDispatch.cpp +++ b/public-trunk/Control/DCCHDispatch.cpp @@ -102,14 +102,18 @@ void DCCHDispatchRR(const L3RRMessage* req, LogicalChannel *DCCH) /** Example of a closed-loop, persistent-thread control function for the DCCH. */ void Control::DCCHDispatcher(LogicalChannel *DCCH) { + const L3Message *message = NULL; while (1) { try { - // Wait for a transaction to start. - LOG(DEBUG) << "waiting for " << DCCH->type() << " ESTABLISH"; - waitForPrimitive(DCCH,ESTABLISH); - // Pull the first message and dispatch a new transaction. - const L3Message *message = getMessage(DCCH); - LOG(DEBUG) << "received " << *message; + if (!message) + { + // Wait for a transaction to start. + LOG(DEBUG) << "waiting for " << DCCH->type() << " ESTABLISH"; + waitForPrimitive(DCCH,ESTABLISH); + // Pull the first message and dispatch a new transaction. + message = getMessage(DCCH); + LOG(DEBUG) << "received " << *message; + } // Each protocol has it's own sub-dispatcher. switch (message->PD()) { case L3MobilityManagementPD: @@ -120,9 +124,12 @@ void Control::DCCHDispatcher(LogicalChannel *DCCH) break; default: LOG(NOTICE) << "unhandled protocol " << message->PD() << " on " << DCCH->type(); + delete message; + message = NULL; throw UnsupportedMessage(); } delete message; + message = NULL; } // Catch the various error cases. @@ -142,8 +149,16 @@ void Control::DCCHDispatcher(LogicalChannel *DCCH) catch (UnexpectedMessage except) { clearTransactionHistory(except.transactionID()); LOG(NOTICE) << "UnexpectedMessage"; - // Cause 0x62 means "message type not not compatible with protocol state". - DCCH->send(L3ChannelRelease(0x62)); + if (except.mpFrame) + { + message = parseL3(*except.mpFrame); + delete except.mpFrame; + } + else + { + // Cause 0x62 means "message type not not compatible with protocol state". + DCCH->send(L3ChannelRelease(0x62)); + } } catch (UnsupportedMessage except) { clearTransactionHistory(except.transactionID()); @@ -175,7 +190,4 @@ void Control::DCCHDispatcher(LogicalChannel *DCCH) } } - - - // vim: ts=4 sw=4 diff --git a/public-trunk/Control/Makefile.am b/public-trunk/Control/Makefile.am index 9a55cd6..8d371dc 100644 --- a/public-trunk/Control/Makefile.am +++ b/public-trunk/Control/Makefile.am @@ -30,12 +30,13 @@ noinst_LTLIBRARIES = libcontrol.la libcontrol_la_SOURCES = \ CallControl.cpp \ SMSControl.cpp \ + USSDControl.cpp \ ControlCommon.cpp \ MobilityManagement.cpp \ RadioResource.cpp \ DCCHDispatch.cpp \ CollectMSInfo.cpp \ - RRLPQueryController.cpp + RRLPQueryController.cpp # TODO - move CollectMSInfo.cpp and RRLPQueryController.cpp to RRLP directory. diff --git a/public-trunk/Control/Makefile.in b/public-trunk/Control/Makefile.in index 96f6237..3a92274 100644 --- a/public-trunk/Control/Makefile.in +++ b/public-trunk/Control/Makefile.in @@ -92,7 +92,7 @@ CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libcontrol_la_LIBADD = -am_libcontrol_la_OBJECTS = CallControl.lo SMSControl.lo \ +am_libcontrol_la_OBJECTS = CallControl.lo SMSControl.lo USSDControl.lo\ ControlCommon.lo MobilityManagement.lo RadioResource.lo \ DCCHDispatch.lo CollectMSInfo.lo RRLPQueryController.lo libcontrol_la_OBJECTS = $(am_libcontrol_la_OBJECTS) @@ -271,6 +271,7 @@ noinst_LTLIBRARIES = libcontrol.la libcontrol_la_SOURCES = \ CallControl.cpp \ SMSControl.cpp \ + USSDControl.cpp \ ControlCommon.cpp \ MobilityManagement.cpp \ RadioResource.cpp \ @@ -344,6 +345,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RRLPQueryController.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RadioResource.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SMSControl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/USSDControl.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ diff --git a/public-trunk/Control/MobilityManagement.cpp b/public-trunk/Control/MobilityManagement.cpp index cad2b16..cf8c7f0 100644 --- a/public-trunk/Control/MobilityManagement.cpp +++ b/public-trunk/Control/MobilityManagement.cpp @@ -64,6 +64,9 @@ void Control::CMServiceResponder(const L3CMServiceRequest* cmsrq, LogicalChannel case L3CMServiceType::EmergencyCall: EmergencyCall(cmsrq,DCCH); break; + case L3CMServiceType::SupplementaryService: + MOUSSDController(cmsrq,DCCH); + break; default: LOG(NOTICE) << "service not supported for " << *cmsrq; // Cause 0x20 means "serivce not supported". diff --git a/public-trunk/Control/RadioResource.cpp b/public-trunk/Control/RadioResource.cpp index 51a7bd2..9fb83c4 100644 --- a/public-trunk/Control/RadioResource.cpp +++ b/public-trunk/Control/RadioResource.cpp @@ -279,6 +279,9 @@ void Control::PagingResponseHandler(const L3PagingResponse* resp, LogicalChannel case L3CMServiceType::MobileTerminatedShortMessage: MTSMSController(transaction, DCCH); return; + case L3CMServiceType::SupplementaryService: + MTUSSDController(transaction, DCCH); + return; default: // Flush stray MOC entries. // There should not be any, but... diff --git a/public-trunk/Control/USSDControl.cpp b/public-trunk/Control/USSDControl.cpp new file mode 100644 index 0000000..a468922 --- /dev/null +++ b/public-trunk/Control/USSDControl.cpp @@ -0,0 +1,405 @@ +/**@file USSD Control (L3) */ +/* +* Copyright 2008, 2009 Free Software Foundation, Inc. +* +* This software is distributed under the terms of the GNU Public License. +* See the COPYING file in the main directory for details. +* +* This use of this software may be subject to additional restrictions. +* See the LEGAL file in the main directory for details. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + + +#include +#include +#include +#include "ControlCommon.h" +#include +#include "GSML3NonCallSSMessages.h" +#include "GSML3NonCallSSComponents.h" +#include "GSML3NonCallSSElements.h" +#include + + +using namespace std; +using namespace GSM; +using namespace Control; + + +#include "SIPInterface.h" +#include "SIPUtility.h" +#include "SIPMessage.h" +#include "SIPEngine.h" +using namespace SIP; + +/** @file USSDControl.cpp + +USSD string coding schema is described at GSM 02.90 5.1.2, 5.1.4 +and GSM 02.30 4.5 + +TODO: +1) We should support Network -> MS USSD too. + +BUGS: +1) *101# does not work with Siemens A52 (but does work with A65). +After phone receives "Send more data" it can't perform any more USSD +and can't reply to this request too. If you try, phone displays +"NOT EXECUTED". BUT when you switch it off afterwards, it sends +ReleaseComplete, so it seems it's stuck waiting for something from +network? + +2) On Alcatel BG3 message sent with Notify disappears as soon as +phone receives our ReleaseComplete. Probably we should delay it +by a few seconds? +*/ + + +L3Frame* getFrameUSSD (LogicalChannel *LCH, GSM::Primitive primitive=DATA) +{ + L3Frame *retVal = LCH->recv(gConfig.getNum("USSD.timeout"),0); + if (!retVal) { + LOG(NOTICE) <<"TIME"; + //throw ChannelReadTimeout(); + retVal = NULL; + } + else if (retVal->primitive() != primitive) { + LOG(NOTICE) << "unexpected primitive, expecting " << primitive << ", got " << *retVal; + //throw UnexpectedPrimitive(); + retVal = NULL; + } + else if ((retVal->primitive() == DATA) && (retVal->PD() != L3NonCallSSPD)) { + LOG(NOTICE) << "unexpected (non-USSD) protocol in frame " << *retVal; + //throw UnexpectedMessage(0, retVal); + retVal = NULL; + } + return retVal; +} + +void USSDSend(string USSDString, unsigned InvokeID, unsigned TI, unsigned TIFlag, LogicalChannel* LCH, Control::USSDData::USSDMessageType messageType) +{ + L3Frame Frame; + + if (TIFlag) TIFlag = 0; + else TIFlag = 1; + + if (messageType == Control::USSDData::REGrequest) + { + //SEND MT REGISTER, UnstructuredSSRequest + L3NonCallSSComponentInvoke* ComponentPtr = new L3NonCallSSComponentInvoke(L3NonCallSSInvokeID(InvokeID), + L3NonCallSSOperationCode(GSM::L3NonCallSSOperationCode::UnstructuredSSRequest)); + ComponentPtr->parameters(L3NonCallSSParameters(USSDString.c_str())); + L3NonCallSSRegisterMessage RegisterMessage(0, 0, ComponentPtr); + RegisterMessage.write(Frame); + LOG(DEBUG) << "Sending Register Message: " << RegisterMessage; + LCH->send(Frame); + } + + else if (messageType == Control::USSDData::request) + { + //SEND MT Facility, UnstructuredSSRequest + L3NonCallSSComponentInvoke* ComponentPtr = new L3NonCallSSComponentInvoke(L3NonCallSSInvokeID(InvokeID), + L3NonCallSSOperationCode(GSM::L3NonCallSSOperationCode::UnstructuredSSRequest)); + ComponentPtr->parameters(L3NonCallSSParameters(USSDString.c_str())); + L3NonCallSSFacilityMessage FacilityMessage(TIFlag, TI, ComponentPtr); + FacilityMessage.write(Frame); + LOG(DEBUG) << "Sending Register Message: " << FacilityMessage; + LCH->send(Frame); + } + + else if (messageType == Control::USSDData::response) + { + //send response + L3NonCallSSComponentReturnResult* ComponentPtr = new L3NonCallSSComponentReturnResult(L3NonCallSSInvokeID(InvokeID)); + ComponentPtr->operationCode(L3NonCallSSOperationCode(GSM::L3NonCallSSOperationCode::ProcessUnstructuredSSRequest)); + ComponentPtr->parameters(L3NonCallSSParameters(USSDString.c_str())); + L3NonCallSSReleaseCompleteMessage ReleaseCompleteMessage(TIFlag, TI); + ReleaseCompleteMessage.component(ComponentPtr); + ReleaseCompleteMessage.write(Frame); + LOG(DEBUG) << "Sending Release Complete Message with response: " << ReleaseCompleteMessage; + LCH->send(Frame); + //send L3 Channel Release + LOG(DEBUG) << "L3 Channel Release."; + LCH->send(L3ChannelRelease()); + } + + else if (messageType == Control::USSDData::request ) + { + //send request + if(InvokeID == 0xff) InvokeID = 0; + else InvokeID++; + L3NonCallSSComponentInvoke* ComponentPtr = new L3NonCallSSComponentInvoke(L3NonCallSSInvokeID(InvokeID), + L3NonCallSSOperationCode(GSM::L3NonCallSSOperationCode::UnstructuredSSRequest)); + + ComponentPtr->parameters(L3NonCallSSParameters(USSDString.c_str())); + L3NonCallSSFacilityMessage FacilityMessage(TIFlag, TI, ComponentPtr); + FacilityMessage.write(Frame); + LOG(DEBUG) << "Sending Facility Message with request: " << FacilityMessage; + LCH->send(Frame); + } + + else if (messageType == Control::USSDData::notify) + { + //send notify + if(InvokeID == 0xff) InvokeID = 0; + else InvokeID++; + L3NonCallSSComponentInvoke* ComponentPtr = new L3NonCallSSComponentInvoke(L3NonCallSSInvokeID(InvokeID), + L3NonCallSSOperationCode(GSM::L3NonCallSSOperationCode::UnstructuredSSNotify)); + ComponentPtr->parameters(L3NonCallSSParameters(USSDString.c_str())); + L3NonCallSSFacilityMessage FacilityMessage(TIFlag, TI, ComponentPtr); + FacilityMessage.write(Frame); + LOG(DEBUG) << "Sending Facility Message with notify: " << FacilityMessage; + LCH->send(Frame); + } + + else if (messageType == Control::USSDData::error) + { + //send error + L3NonCallSSComponentReturnError* ComponentPtr = new L3NonCallSSComponentReturnError(L3NonCallSSInvokeID(InvokeID), + L3NonCallSSErrorCode(GSM::L3NonCallSSErrorCode::SystemFailure)); + L3NonCallSSFacilityMessage FacilityMessage(TIFlag, TI, ComponentPtr); + FacilityMessage.write(Frame); + LOG(DEBUG) << "Sending Facility Message with error System Failure: " << FacilityMessage; + LCH->send(Frame); + } + + else if(messageType == Control::USSDData::release) + { + // NOTE: On some phones (e.g. Nokia 3310, Alcatel BG3) if this parameteris set to a non-empty string, + // when it is sent after Notify USSD, this string is shown on the screen after showing Notify + // message just for a second. I.e. it replaces (obscures) original Notify message. Thus we + // recommend to set this string to an empty string. + L3NonCallSSComponentReturnResult* ComponentPtr = new L3NonCallSSComponentReturnResult(L3NonCallSSInvokeID(InvokeID)); + ComponentPtr->operationCode(L3NonCallSSOperationCode(GSM::L3NonCallSSOperationCode::ProcessUnstructuredSSRequest)); + ComponentPtr->parameters(L3NonCallSSParameters("release")); + L3NonCallSSReleaseCompleteMessage ReleaseCompleteMessage(TIFlag, TI); + if (TIFlag == 1) + { + ReleaseCompleteMessage.component(ComponentPtr); + } + ReleaseCompleteMessage.write(Frame); + LOG(DEBUG) << "Sending Release Complete Message: " << ReleaseCompleteMessage; + LCH->send(Frame); + //send L3 Channel Release + LOG(DEBUG) << "L3 Channel Release."; + LCH->send(L3ChannelRelease()); + } + + + +} + +Control::USSDData::USSDMessageType USSDParse(L3NonCallSSMessage* Message, string* USSDString, unsigned* InvokeID ) +{ + L3Frame Frame; + Control::USSDData::USSDMessageType messageType = Control::USSDData::error; + // Low-level mesage flow is described at GSM 04.90 6.1. + // High-level message flow is described at GSM 03.90 6.2. + + // Process REQUEST message + if (Message->MTI() == GSM::L3NonCallSSMessage::Register) + { + LOG(DEBUG) << "Received Register Message"; + L3NonCallSSRegisterMessage* RegisterMessage = (L3NonCallSSRegisterMessage*)Message; + if (RegisterMessage->l3NonCallSSComponent()->NonCallSSComponentTypeTag()== GSM::L3NonCallSSComponent::Invoke) + { + LOG(DEBUG) << "Received Invoke Component"; + L3NonCallSSComponentInvoke* Component; + Component = (L3NonCallSSComponentInvoke*)RegisterMessage->l3NonCallSSComponent(); + *USSDString = Component->l3NonCallSSParameters().data(); + LOG(DEBUG) << "Read USSD string"; + *InvokeID = (unsigned)Component->invokeID().value(); + messageType = Control::USSDData::request; + } + + } + // Process RESPONSE message + else if (Message->MTI() == GSM::L3NonCallSSMessage::Facility) + { + LOG(DEBUG) << "Received Facility Message"; + L3NonCallSSFacilityMessage* FacilityMessage = (L3NonCallSSFacilityMessage*)Message; + if (FacilityMessage->l3NonCallSSComponent()->NonCallSSComponentTypeTag()== GSM::L3NonCallSSComponent::ReturnResult) + { + LOG(DEBUG) << "Return Result Component"; + L3NonCallSSComponentReturnResult* Component; + Component = (L3NonCallSSComponentReturnResult*)FacilityMessage->l3NonCallSSComponent(); + if (Component->haveL3NonCallSSParameters()) *USSDString = Component->l3NonCallSSParameters().data(); + else *USSDString = ""; + *InvokeID = (unsigned)Component->invokeID().value(); + messageType = Control::USSDData::response; + } + } + + // Process RELEASE or ERROR + else // MTI == GSM::L3NonCallSSMessage::ReleaseComplete + { + L3NonCallSSReleaseCompleteMessage* ReleaseCompleteMessage = (L3NonCallSSReleaseCompleteMessage*)Message; + if (ReleaseCompleteMessage->haveL3NonCallSSComponent()) + { + *InvokeID = ReleaseCompleteMessage->l3NonCallSSComponent()->invokeID().value(); + messageType = Control::USSDData::release; + } + else + { + InvokeID = 0; + messageType = Control::USSDData::release; + } + *USSDString = ""; + } + + return messageType; +} + +void Control::MOUSSDController(const L3CMServiceRequest *request, LogicalChannel *LCH) +{ + assert(request); + assert(LCH); + + LOG(DEBUG) << "Get L3 CM Service Request: " << *request; + L3MobileIdentity mobileIdentity = request->mobileIdentity(); + LOG(DEBUG) << "mobileIdentity: "<send(L3CMServiceAccept()); + + //Get USSD frame from MS + LOG(DEBUG) << "Get USSD frame from MS"; + L3Frame *USSDFrame = getFrameUSSD(LCH); + //Parse USSD frame + LOG(DEEPDEBUG) << "Parse USSD frame"; + L3NonCallSSMessage* USSDMessage; + USSDMessage = parseL3NonCallSS(*USSDFrame); + LOG(INFO) << "USSD message:"<<*USSDMessage; + + string USSDString = ""; + unsigned InvokeID = 0; + + Control::USSDData::USSDMessageType messageType = USSDParse(USSDMessage, &USSDString, &InvokeID); + unsigned transactionID = USSDDispatcher (mobileIdentity, USSDMessage->TIFlag(), USSDMessage->TIValue(), messageType, USSDString, true); + unsigned TI = USSDMessage->TIValue(); + + TransactionEntry transaction; + while(gTransactionTable.find(transactionID, transaction)) + { + if (transaction.Q931State() == Control::TransactionEntry::USSDclosing) + { + break; + } + else if (transaction.ussdData()->waitNW()==0) + { + gTransactionTable.find(transactionID, transaction); + //SEND + USSDSend(transaction.ussdData()->USSDString(), InvokeID, TI, 0, LCH, transaction.ussdData()->MessageType()); + if((transaction.ussdData()->MessageType() == Control::USSDData::response)|| + (transaction.ussdData()->MessageType() == Control::USSDData::release)) + { + LOG(DEBUG) << "USSD waitMS response||relese"; + transaction.Q931State(Control::TransactionEntry::USSDclosing); + } + else + { + //RECV + L3Frame *USSDFrame = getFrameUSSD(LCH); + if (USSDFrame == NULL) + { + USSDSend(transaction.ussdData()->USSDString(), InvokeID, TI, 0, LCH, Control::USSDData::release); + transaction.Q931State(Control::TransactionEntry::USSDclosing); + } + else + { + //Parse USSD frame + L3NonCallSSMessage* USSDMessage = parseL3NonCallSS(*USSDFrame); + TI = USSDMessage->TIValue(); + LOG(INFO) << "USSD message before PARSE:"<<*USSDMessage; + Control::USSDData::USSDMessageType messageType = USSDParse(USSDMessage, &USSDString, &InvokeID); + LOG(INFO) << "MO USSD message: "<< *USSDMessage << " MO USSD type: "<< messageType + << " USSD string: " << USSDString << " InvokeID: " << InvokeID; + transaction.ussdData()->USSDString(USSDString); + transaction.ussdData()->MessageType(messageType); + delete USSDMessage; + } + delete USSDFrame; + + } + gTransactionTable.update(transaction); + transaction.ussdData()->postMS(); + } + } +} + + +void Control::MTUSSDController(TransactionEntry& transaction, LogicalChannel *LCH) +{ + + assert(LCH); + LOG(INFO) << "MTUSSD: transaction: "<< transaction; + LCH->transactionID(transaction.ID()); + string USSDString = ""; + unsigned InvokeID = 0; + unsigned TI = 0; + unsigned transactionID = transaction.ID(); + + transaction.Q931State(Control::TransactionEntry::USSDworking); + gTransactionTable.update(transaction); + + while(gTransactionTable.find(transactionID, transaction)) + { + if (transaction.Q931State() == Control::TransactionEntry::USSDclosing) + { + break; + } + else if (transaction.ussdData()->waitNW()==0) + { + gTransactionTable.find(transactionID, transaction); + //SEND + USSDSend(transaction.ussdData()->USSDString(), InvokeID, TI, 1, LCH, transaction.ussdData()->MessageType()); + if((transaction.ussdData()->MessageType() == Control::USSDData::response)|| + (transaction.ussdData()->MessageType() == Control::USSDData::release)) + { + LOG(DEBUG) << "USSD waitMS response||relese"; + transaction.Q931State(Control::TransactionEntry::USSDclosing); + } + else + { + //RECV + L3Frame *USSDFrame = getFrameUSSD(LCH); + if (USSDFrame == NULL) + { + USSDSend(transaction.ussdData()->USSDString(), InvokeID, TI, 1, LCH, Control::USSDData::release); + transaction.Q931State(Control::TransactionEntry::USSDclosing); + } + else + { + //Parse USSD frame + L3NonCallSSMessage* USSDMessage = parseL3NonCallSS(*USSDFrame); + TI = USSDMessage->TIValue(); + Control::USSDData::USSDMessageType messageType = USSDParse(USSDMessage, &USSDString, &InvokeID); + LOG(INFO) << "MT USSD message: "<< *USSDMessage << "MT USSD type: "<< messageType + << " USSD string: " << USSDString << " InvokeID: " << InvokeID; + transaction.ussdData()->MessageType(messageType); + transaction.ussdData()->USSDString(USSDString); + delete USSDMessage; + } + delete USSDFrame; + } + gTransactionTable.update(transaction); + transaction.ussdData()->postMS(); + } + } + + LOG(DEBUG) << "USSD session done."; +} + + diff --git a/public-trunk/GSM/GSML2LAPDm.cpp b/public-trunk/GSM/GSML2LAPDm.cpp index e367c6f..df08d47 100644 --- a/public-trunk/GSM/GSML2LAPDm.cpp +++ b/public-trunk/GSM/GSML2LAPDm.cpp @@ -980,9 +980,10 @@ void L2LAPDm::sendIFrame(const BitVector& payload, bool MBit) bool L2LAPDm::stuckChannel(const L2Frame& frame) { // Check for excessive idling. - if (frame.DCCHIdle()) mIdleCount++; - else mIdleCount=0; - return mIdleCount > maxIdle(); + //if (frame.DCCHIdle()) mIdleCount++; + //else mIdleCount=0; + //return mIdleCount > maxIdle(); + return false; } diff --git a/public-trunk/GSM/GSML3Message.cpp b/public-trunk/GSM/GSML3Message.cpp index a4e3063..bd62ffb 100644 --- a/public-trunk/GSM/GSML3Message.cpp +++ b/public-trunk/GSM/GSML3Message.cpp @@ -28,6 +28,7 @@ #include "GSML3RRMessages.h" #include "GSML3MMMessages.h" #include "GSML3CCMessages.h" +#include "GSML3NonCallSSMessages.h" #include @@ -148,6 +149,7 @@ GSM::L3Message* GSM::parseL3(const GSM::L3Frame& source) case L3RadioResourcePD: retVal=parseL3RR(source); break; case L3MobilityManagementPD: retVal=parseL3MM(source); break; case L3CallControlPD: retVal=parseL3CC(source); break; + case L3NonCallSSPD: retVal=parseL3NonCallSS(source); break; //case L3SMSPD: return parseSMS(source); default: LOG(NOTICE) << "L3 parsing failed for unsupported protocol " << PD; diff --git a/public-trunk/GSM/GSML3NonCallSSComponents.cpp b/public-trunk/GSM/GSML3NonCallSSComponents.cpp new file mode 100644 index 0000000..1eb0449 --- /dev/null +++ b/public-trunk/GSM/GSML3NonCallSSComponents.cpp @@ -0,0 +1,295 @@ +/**@file Call independent Supplementary Service Control. Facility element components, GSM 04.80 3.6.1. */ + +/* +* Copyright 2008, 2009 Free Software Foundation, Inc. +* +* This software is distributed under the terms of the GNU Public License. +* See the COPYING file in the main directory for details. +* +* This use of this software may be subject to additional restrictions. +* See the LEGAL file in the main directory for details. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + +#include +#include "GSML3NonCallSSComponents.h" +#include + + + +using namespace std; +using namespace GSM; + + +ostream& GSM::operator<<(ostream& os, const L3NonCallSSComponent& msg) +{ + msg.text(os); + return os; +} + +ostream& GSM::operator<<(std::ostream& os, L3NonCallSSComponent::ComponentTypeTag val) +{ + switch (val) { + case L3NonCallSSComponent::Invoke: + os << "Invoke"; break; + case L3NonCallSSComponent::ReturnResult: + os << "ReturnResult"; break; + case L3NonCallSSComponent::ReturnError: + os << "ReturnError"; break; + case L3NonCallSSComponent::Reject: + os << "Reject"; break; + default: os << hex << "0x" << (int)val << dec; + } + + return os; +} + +L3NonCallSSComponent * GSM::L3NonCallSSComponentFactory(L3NonCallSSComponent::ComponentTypeTag CTT) +{ + switch (CTT) { + case L3NonCallSSComponent::Invoke: return new L3NonCallSSComponentInvoke(); + case L3NonCallSSComponent::ReturnResult: return new L3NonCallSSComponentReturnResult(); + case L3NonCallSSComponent::ReturnError: return new L3NonCallSSComponentReturnError(); + case L3NonCallSSComponent::Reject: return new L3NonCallSSComponentReject(); + default: { + //LOG(NOTICE) << "no L3 NonCallSSComponent factory support for message "<< CTT; + return NULL; + } + } +} + +L3NonCallSSComponent * GSM::parseL3NonCallSSComponent (const L3Frame& source, size_t &rp) +{ + L3NonCallSSComponent::ComponentTypeTag CTT = (L3NonCallSSComponent::ComponentTypeTag)source.readField(rp, 8); + LOG(DEBUG) << "Component Type Tag = "<<(int)CTT; + + L3NonCallSSComponent *retVal = L3NonCallSSComponentFactory(CTT); + if (retVal==NULL) return NULL; + + retVal->parse(source,rp); + LOG(DEBUG) << "parse L3 Non Call SS Component " << *retVal; + return retVal; +} + +void L3NonCallSSComponent::write(L3Frame& dest, size_t &wp) +{ + dest.writeField(wp,NonCallSSComponentTypeTag(),8);//Component type tag + writeBody(dest,wp); +} + +void L3NonCallSSComponent::parse(const L3Frame& source, size_t &rp) +{ + mComponentLength.parseV(source,rp);//ComponentLength + rp+=16;//InvokeID Tag and InvokeIDLength + mInvokeID.parseV(source, rp, 1);//InvokeID + parseBody(source, rp); +} + +void L3NonCallSSComponent::text(ostream& os) const +{ + os << " ComponentTypeTag = " << NonCallSSComponentTypeTag(); + os << " InvokeID = " << mInvokeID; +} + + +void L3NonCallSSComponentInvoke::writeBody( L3Frame &dest, size_t &wp ) +{ + this->length(); + mComponentLength.writeV(dest, wp);//ComponentLength + dest.writeField(wp,0x2,8);//InvokeID tag + dest.writeField(wp,0x1,8);//InvokeIDLength + mInvokeID.writeV(dest,wp,8);//InvokeID + if (mHaveLinkedID) + { + dest.writeField(wp,0x80,8);//LinkedID tag + dest.writeField(wp,0x1,8);//LinkedIDLength + mLinkedID.writeV(dest, wp, 8);//LinkedID + } + dest.writeField(wp,0x2,8);//Operation Cod tag + dest.writeField(wp,0x1,8);//Operation Cod length + mOperationCode.writeV(dest, wp); //Operation Cod + if(mHaveParameters) + { + mParameters.write(dest, wp);//Parameters + } +} + +void L3NonCallSSComponentInvoke::parseBody( const L3Frame &source, size_t &rp ) +{ + if(source.readField(rp, 8) == 0x80) + { + rp+=8;//LinkedID tag and LinkedIDLength + mLinkedID.parseV(source, rp, 1);//LinkedID + mHaveLinkedID = true; + } + rp+=8;//OperationCodTag and OperationCodLength + mOperationCode.parseV(source, rp);//OperationCode + if((mComponentLength.value()>9)&&(source.readField(rp, 8) == 0x30)) + { + rp-=8; + mParameters.parseV(source, rp);//Parameters + mHaveParameters = true; + } +} + +size_t L3NonCallSSComponentInvoke::length() +{ + uint64_t ComponentLength = 0x6; + if (mHaveLinkedID) { ComponentLength += 0x3; } + if(mHaveParameters) { ComponentLength += mParameters.length(); } + mComponentLength.setValue(ComponentLength); + return mComponentLength.value()+mComponentLength.lengthV()+0x1; +} + +void L3NonCallSSComponentInvoke::text(std::ostream& os) const +{ + L3NonCallSSComponent::text(os); + + if (mHaveLinkedID) os << " LinkedID = " << mLinkedID; + os << " OperationCode = " << mOperationCode; + if (mHaveParameters) os << " Parameters = (" << mParameters<< ")"; +} + +void L3NonCallSSComponentReturnResult::writeBody( L3Frame &dest, size_t &wp ) +{ + this->length(); + mComponentLength.writeV(dest, wp);//ComponentLength + dest.writeField(wp,0x2,8);//InvokeID tag + dest.writeField(wp,0x1,8);//InvokeIDLength + mInvokeID.writeV(dest,wp,8);//InvokeID + if(mHaveParameters) + { + dest.writeField(wp,0x30,8); //Sequence tag + mSequenceLength.writeV(dest, wp);//SequenceLength + dest.writeField(wp,0x2,8);//Operation Cod tag + dest.writeField(wp,0x1,8);//Operation Cod length + mOperationCode.writeV(dest, wp); //Operation Cod + mParameters.write(dest, wp);//Parameters + } +} + +void L3NonCallSSComponentReturnResult::parseBody( const L3Frame &source, size_t &rp ) +{ + if ((mComponentLength.value() > 0x3)&&(source.readField(rp, 8) == 0x30)) + { + mSequenceLength.parseV(source,rp);//SequenceLength + rp+=16;//OperationCodTag and OperationCodLength + mOperationCode.parseV(source, rp);//OperationCode + mParameters.parseV(source, rp);//Parameters + mHaveParameters = true; + } +} + +size_t L3NonCallSSComponentReturnResult::length() +{ + uint64_t ComponentLength = 0x3; + if(mHaveParameters) + { + + mSequenceLength.setValue(mParameters.length()+0x3); + ComponentLength += mSequenceLength.value() + mSequenceLength.lengthV() + 0x1; + } + mComponentLength.setValue(ComponentLength); + return mComponentLength.value()+mComponentLength.lengthV()+0x1; +} + +void L3NonCallSSComponentReturnResult::text(std::ostream& os) const +{ + L3NonCallSSComponent::text(os); + if (mHaveParameters) + { + os << " OperationCode = " << mOperationCode; + os << " Parameters = (" << mParameters << ")"; + } +} + +void L3NonCallSSComponentReturnError::writeBody( L3Frame &dest, size_t &wp ) +{ + this->length(); + mComponentLength.writeV(dest, wp);//ComponentLength + dest.writeField(wp,0x2,8);//InvokeID tag + dest.writeField(wp,0x1,8);//InvokeIDLength + mInvokeID.writeV(dest,wp,8);//InvokeID + dest.writeField(wp,0x2,8);//Error Cod tag + dest.writeField(wp,0x1,8);//Error Cod length + mErrorCode.writeV(dest, wp); //Error Cod + if(mHaveParameters) + { + mParameters.write(dest, wp);//Parameters + } +} + +void L3NonCallSSComponentReturnError::parseBody( const L3Frame &source, size_t &rp ) +{ + rp+=16;//ErrorCodTag and ErrorCodLength + mErrorCode.parseV(source, rp);//ErrorCode + if((mComponentLength.value() > 0x6)&&(source.readField(rp, 8) == 0x30)) + { + rp-=8; + mParameters.parseV(source, rp);//Parameters + mHaveParameters = true; + } +} + +size_t L3NonCallSSComponentReturnError::length() +{ + uint64_t ComponentLength = 0x6; + if(mHaveParameters) { ComponentLength += mParameters.length();} + mComponentLength.setValue(ComponentLength); + return mComponentLength.value()+mComponentLength.lengthV()+0x1; +} + +void L3NonCallSSComponentReturnError::text(std::ostream& os) const +{ + L3NonCallSSComponent::text(os); + os << " ErrorCode = " << mErrorCode; + if (mHaveParameters) os << " Parameters = " << mParameters; +} + +void L3NonCallSSComponentReject::writeBody( L3Frame &dest, size_t &wp ) +{ + this->length(); + mComponentLength.writeV(dest, wp);//ComponentLength + dest.writeField(wp,0x6,8);//ComponentLength + dest.writeField(wp,0x2,8);//InvokeID tag + dest.writeField(wp,0x1,8);//InvokeIDLength + mInvokeID.writeV(dest,wp,8);//InvokeID + mProblemCodeTag.writeV(dest, wp);//Problem Code Tag + dest.writeField(wp,0x1,8);//Problem Code length + mProblemCode.writeV(dest, wp); //Problem Code Cod +} + +void L3NonCallSSComponentReject::parseBody( const L3Frame &source, size_t &rp ) +{ + mProblemCodeTag.parseV(source, rp);//ProblemCodeTag + rp+=8;//Problem Code length + mProblemCode.parseV(source, rp);//ProblemCode +} + +size_t L3NonCallSSComponentReject::length() +{ + mComponentLength.setValue(0x6); + return mComponentLength.value()+mComponentLength.lengthV()+0x1; +} + + +void L3NonCallSSComponentReject::text(std::ostream& os) const +{ + L3NonCallSSComponent::text(os); + os << " ProblemCodeTag = " << mProblemCodeTag; + os << " ProblemCode = " << mProblemCode; +} diff --git a/public-trunk/GSM/GSML3NonCallSSComponents.h b/public-trunk/GSM/GSML3NonCallSSComponents.h new file mode 100644 index 0000000..82c9ef4 --- /dev/null +++ b/public-trunk/GSM/GSML3NonCallSSComponents.h @@ -0,0 +1,270 @@ +/**@file Call independent Supplementary Service Control. Facility element components, GSM 04.80 3.6.1. */ +/* +* Copyright 2008 Free Software Foundation, Inc. +* +* This software is distributed under the terms of the GNU Public License. +* See the COPYING file in the main directory for details. +* +* This use of this software may be subject to additional restrictions. +* See the LEGAL file in the main directory for details. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + + +#ifndef GSML3NONCALLSSCOMPONENT_H +#define GSML3NONCALLSSCOMPONENT_H + +#include "GSML3NonCallSSElements.h" +#include "assert.h" + +namespace GSM { + +/** +This is virtual base class for the facility element components, GSM 04.80 3.6.1. +*/ +class L3NonCallSSComponent { + + protected: + + L3NonCallSSInvokeID mInvokeID; + L3NonCallSSLengthField mComponentLength; + + public: + + enum ComponentTypeTag { + Invoke = 0xa1, + ReturnResult = 0xa2, + ReturnError = 0xa3, + Reject = 0xa4 + }; + + L3NonCallSSComponent (const L3NonCallSSInvokeID& wInvokeID = L3NonCallSSInvokeID()) + :mInvokeID(wInvokeID), + mComponentLength(L3NonCallSSLengthField()) + {} + + /** Return the expected component body length in bytes */ + virtual size_t length() = 0; + + /** Return number of BITS needed to hold component. */ + size_t bitsNeeded() { return 8*length(); } + + /** + The parse() method reads and decodes L3 NonCallSS facility component bits. + This method invokes parseBody, assuming that the component header + has already been read. + */ + virtual void parse(const L3Frame& source, size_t &rp); + + /** + Write component data bits into a BitVector buffer. + This method invokes writeBody. + */ + virtual void write(L3Frame& dest, size_t &wp); + + /** Return the ComponentTypeTag. */ + virtual ComponentTypeTag NonCallSSComponentTypeTag() const =0; + + const L3NonCallSSInvokeID& invokeID() const { return mInvokeID; } + + protected: + + /** + Write the component body, a method defined in some subclasses. + */ + virtual void writeBody(L3Frame& dest, size_t &writePosition) =0; + + /** + The parseBody() method starts processing at the first byte following the + invokeID field in the component, which the caller indicates with the + readPosition argument. + */ + virtual void parseBody(const L3Frame& source, size_t &readPosition) =0; + + public: + + /** Generate a human-readable representation of a component. */ + virtual void text(std::ostream& os) const; + +}; + + +std::ostream& operator<<(std::ostream& os, L3NonCallSSComponent::ComponentTypeTag CTT); + +/** +Parse facility component into its object type. +@param source The L3 bits. +@return A pointer to a new component or NULL on failure. +*/ +L3NonCallSSComponent* parseL3NonCallSSComponent(const L3Frame& source, size_t &rp); + +/** +A Factory function to return a L3NonCallSSComponent of the specified CTT. +Returns NULL if the CTT is not supported. +*/ +L3NonCallSSComponent* L3NonCallSSComponentFactory(L3NonCallSSComponent::ComponentTypeTag CTT); + +std::ostream& operator<<(std::ostream& os, const GSM::L3NonCallSSComponent& msg); + +/** Invoke component GSM 04.80 3.6.1 Table 3.3 */ +class L3NonCallSSComponentInvoke : public L3NonCallSSComponent { + + private: + + //Mandatory + L3NonCallSSOperationCode mOperationCode; + //Optionally + L3NonCallSSLinkedID mLinkedID; + L3NonCallSSParameters mParameters; + bool mHaveLinkedID; + bool mHaveParameters; + + public: + + L3NonCallSSComponentInvoke( + const L3NonCallSSInvokeID& wInvokeID = 1, + const L3NonCallSSOperationCode& wOperationCode = L3NonCallSSOperationCode()) + :L3NonCallSSComponent(wInvokeID), + mOperationCode(wOperationCode), + mHaveLinkedID(false), + mHaveParameters(false) + {} + + void linkedID (L3NonCallSSLinkedID LinkedID) {mLinkedID = LinkedID; mHaveLinkedID = true;} + void parameters (L3NonCallSSParameters Parameters) {mParameters = Parameters; mHaveParameters = true;} + + const L3NonCallSSOperationCode& operationCode() const {return mOperationCode;} + const L3NonCallSSLinkedID& l3NonCallSSLinkedID() const {assert(mHaveLinkedID); return mLinkedID;} + const L3NonCallSSParameters& l3NonCallSSParameters() const {assert (mHaveParameters); return mParameters;} + + bool haveL3NonCallSSLinkedID() const {return mHaveLinkedID;} + bool haveL3NonCallSSParameters() const {return mHaveParameters;} + + ComponentTypeTag NonCallSSComponentTypeTag() const { return Invoke; } + void writeBody( L3Frame &dest, size_t &wp ); + void parseBody( const L3Frame &src, size_t &rp ); + size_t length(); + void text(std::ostream&) const; + +}; + +/**Return Result component GSM 04.80 3.6.1 Table 3.4 */ +class L3NonCallSSComponentReturnResult : public L3NonCallSSComponent { + + private: + + //Optionally + L3NonCallSSOperationCode mOperationCode; + L3NonCallSSParameters mParameters; + L3NonCallSSLengthField mSequenceLength; + bool mHaveParameters; + + public: + + L3NonCallSSComponentReturnResult(const L3NonCallSSInvokeID& wInvokeID = 1) + :L3NonCallSSComponent(wInvokeID), + mSequenceLength(L3NonCallSSLengthField()), + mHaveParameters(false) + {} + + void operationCode (L3NonCallSSOperationCode OperationCode) {mOperationCode = OperationCode;} + void parameters (L3NonCallSSParameters Parameters) {mParameters = Parameters; mHaveParameters = true;} + + const L3NonCallSSOperationCode& l3NonCallSSOperationCode() const {return mOperationCode;} + const L3NonCallSSParameters& l3NonCallSSParameters() const {assert(mHaveParameters); return mParameters;} + + bool haveL3NonCallSSParameters() const {return mHaveParameters;} + + ComponentTypeTag NonCallSSComponentTypeTag() const { return ReturnResult; } + void writeBody( L3Frame &dest, size_t &wp ); + void parseBody( const L3Frame &src, size_t &rp ); + size_t length(); + void text(std::ostream&) const; + +}; + +/** Return Error component GSM 04.80 3.6.1 Table 3.5 */ +class L3NonCallSSComponentReturnError : public L3NonCallSSComponent { + + private: + + //Mandatory + L3NonCallSSErrorCode mErrorCode; + //Optionally + L3NonCallSSParameters mParameters; + bool mHaveParameters; + + public: + + L3NonCallSSComponentReturnError( + const L3NonCallSSInvokeID& wInvokeID = 1, + const L3NonCallSSErrorCode& wErrorCode = L3NonCallSSErrorCode()) + :L3NonCallSSComponent(wInvokeID), + mErrorCode(wErrorCode), + mHaveParameters(false) + {} + + void parameters (L3NonCallSSParameters Parameters) {mParameters = Parameters; mHaveParameters = true;} + + const L3NonCallSSErrorCode& errorCode() const {return mErrorCode;} + const L3NonCallSSParameters& l3NonCallSSParameters() const {assert(mHaveParameters); return mParameters;} + ComponentTypeTag NonCallSSComponentTypeTag() const { return ReturnError; } + + bool haveL3NonCallSSParameters() const {return mHaveParameters;} + + void writeBody( L3Frame &dest, size_t &wp ); + void parseBody( const L3Frame &src, size_t &rp ); + size_t length(); + void text(std::ostream&) const; + +}; + +/** Reject component GSM 04.80 3.6.1 Table 3.6 */ +class L3NonCallSSComponentReject : public L3NonCallSSComponent { + + private: + + //Mandatory + L3NonCallSSProblemCodeTag mProblemCodeTag; + L3NonCallSSProblemCode mProblemCode; + + public: + + //Mandatory ProblemCodeTag and ProblemCode + L3NonCallSSComponentReject( + const L3NonCallSSInvokeID& wInvokeID = 1, + const L3NonCallSSProblemCodeTag& wProblemCodeTag = L3NonCallSSProblemCodeTag(), + const L3NonCallSSProblemCode& wProblemCode = L3NonCallSSProblemCode()) + :L3NonCallSSComponent (wInvokeID), + mProblemCodeTag(wProblemCodeTag), + mProblemCode(wProblemCode) + {} + + + const L3NonCallSSProblemCodeTag& problemCodeTag() const {return mProblemCodeTag;} + const L3NonCallSSProblemCode& problemCode() const {return mProblemCode;} + + ComponentTypeTag NonCallSSComponentTypeTag() const { return Reject; } + void writeBody( L3Frame &dest, size_t &wp ); + void parseBody( const L3Frame &src, size_t &rp ); + size_t length(); + void text(std::ostream&) const; + +}; + +} +#endif diff --git a/public-trunk/GSM/GSML3NonCallSSElements.cpp b/public-trunk/GSM/GSML3NonCallSSElements.cpp new file mode 100644 index 0000000..28e77f7 --- /dev/null +++ b/public-trunk/GSM/GSML3NonCallSSElements.cpp @@ -0,0 +1,214 @@ +/**@file Elements for call independent Supplementary Service Control, GSM 04.80 3. */ +/* +* Copyright 2008, 2009 Free Software Foundation, Inc. +* +* This software is distributed under the terms of the GNU Public License. +* See the COPYING file in the main directory for details. +* +* This use of this software may be subject to additional restrictions. +* See the LEGAL file in the main directory for details. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + + + +#include "GSML3NonCallSSElements.h" +#include + +using namespace std; +using namespace GSM; + + +void L3NonCallSSElementOctetLength::writeV( L3Frame& dest, size_t &wp ) const +{ + dest.writeField(wp,mValue,8); +} + +void L3NonCallSSElementOctetLength::parseV( const L3Frame& src, size_t &rp) +{ + mValue = src.readField(rp, 8); + setValue(); +} + + +size_t L3NonCallSSElementUndefLength::lengthV() const +{ + size_t size = sizeof(mValue); + uint64_t tmp = 0; + do + { + size--; + tmp = mValue>>(size*8); + + } while ((tmp == 0) &&(size>0)); + size++; + return size; +} + +void L3NonCallSSElementUndefLength::writeV( L3Frame& dest, size_t &wp ) const +{ + dest.writeField(wp,mValue,lengthV()*8); +} + +void L3NonCallSSElementUndefLength::writeV( L3Frame& dest, size_t &wp, size_t numBits) const +{ + dest.writeField(wp,mValue,numBits); +} + +void L3NonCallSSElementUndefLength::parseV( const L3Frame& src, size_t &rp, size_t numOctets) +{ + mValue = src.readField(rp, numOctets*8); +} + + +void L3NonCallSSOperationCode::text(ostream& os) const +{ + switch (mOperationCode){ + case ProcessUnstructuredSSRequest: + os << "ProcessUnstructuredSSRequest"; break; + case UnstructuredSSRequest: + os << "UnstructuredSSRequest"; break; + case UnstructuredSSNotify: + os << "UnstructuredSSNotify"; break; + } +} + +size_t L3NonCallSSLengthField::lengthV() const +{ + size_t length = 0; + if (mValue <= 0x7f) length = 1; + else + { + uint64_t tmp = mValue; + do + { + length++; + tmp>>=8; + } while(tmp!=0); + length++; + } + return length; +} + +void L3NonCallSSLengthField::writeV( L3Frame& dest, size_t &wp ) const +{ + if (mValue <= 0x7f) { dest.writeField(wp,mValue,8); } + else + { + uint64_t tmp = mValue; + size_t numOctets = 0; + do + { + numOctets++; + tmp>>=8; + } while(tmp!=0); + dest.writeField(wp,numOctets|0x80,8); + dest.writeField(wp,mValue,numOctets*8); + } +} + +void L3NonCallSSLengthField::parseV( const L3Frame& source, size_t &rp) +{ + uint64_t tmp = source.readField(rp, 8); + if ((tmp>>7)==0) mValue = tmp; + else mValue = source.readField(rp, (tmp&0x7f)*8); +} + +size_t L3NonCallSSParameters::length() +{ + unsigned numChar = strlen(mData); + unsigned ussdStringLength = (numChar*7)/8; + if ((numChar*7)%8!=0) ussdStringLength +=1; + mDataLength.setValue(ussdStringLength); + unsigned sequenceLength = mDataLength.value()+mDataLength.lengthV()+4; + if (mHaveAlertingPattern) sequenceLength+=0x3; + mSequenceLength.setValue(sequenceLength); + return mSequenceLength.value()+mSequenceLength.lengthV()+1; +} + + + +void L3NonCallSSParameters::parseV(const L3Frame& src, size_t& rp) +{ + rp+=8; + mSequenceLength.parseV(src, rp); + rp+=16; + mDataCodingScheme = src.readField(rp,8); + rp+=8; + mDataLength.parseV(src, rp); + unsigned numChar = mDataLength.value()*8/7; + BitVector chars(src.tail(rp)); + chars.LSB8MSB(); + size_t crp=0; + for (int i=0; i + + +namespace GSM { + +/** +This a virtual class for L3 call independent Supplementary Service Control Elements +with length one octet. +*/ +class L3NonCallSSElementOctetLength : public L3ProtocolElement { + + protected: + + uint64_t mValue; + virtual void setValue() = 0; + + public: + + L3NonCallSSElementOctetLength(uint64_t wValue = 0) + :L3ProtocolElement(), + mValue(wValue) + {} + + size_t lengthV() const { return 1; } + void writeV( L3Frame& dest, size_t &wp) const; + void parseV(const L3Frame&, size_t&, size_t) { abort(); } + void parseV(const L3Frame& src, size_t& rp); + +}; + + +/** +This a virtual class for L3 call independent Supplementary Service Control Elements +with undefined length. +*/ +class L3NonCallSSElementUndefLength : public L3ProtocolElement { + + protected: + + uint64_t mValue; + + public: + + L3NonCallSSElementUndefLength(uint64_t wValue = 0) + :L3ProtocolElement(), + mValue(wValue) + {} + + size_t lengthV() const; + void writeV( L3Frame& dest, size_t &wp) const; + void writeV( L3Frame& dest, size_t &wp, size_t numOctets) const; + void parseV(const L3Frame&, size_t&, size_t expectedLength); + void parseV(const L3Frame& src, size_t& rp){ abort(); } + void text(std::ostream& os) const {os << mValue;} + uint64_t value() const { return mValue; } + +}; + +/** +Classes for L3 call independent Supplementary Service Control Elements, GSM 04.80 3 and GSM 04.80 2. +*/ + +class L3NonCallSSComponentTypeTag : public L3NonCallSSElementOctetLength { + + public: + + /** GSM 04.80, Table 3.7 */ + enum ComponentTypeTag { + Invoke = 0xa1, + ReturnResult = 0xa2, + ReturnError = 0xa3, + Reject = 0xa4 + }; + + private: + + ComponentTypeTag mComponentTypeTag; + void setValue () {mComponentTypeTag = (ComponentTypeTag)mValue;} + + public: + + L3NonCallSSComponentTypeTag(ComponentTypeTag wComponentTypeTag = Invoke) + :L3NonCallSSElementOctetLength(wComponentTypeTag), + mComponentTypeTag(wComponentTypeTag) + {} + void text(std::ostream& os) const {os << mComponentTypeTag;} + ComponentTypeTag NonCallSSComponentTypeTag() const {return mComponentTypeTag;} + +}; + +class L3NonCallSSOperationCode : public L3NonCallSSElementOctetLength { + + public: + + enum OperationCode { + ProcessUnstructuredSSRequest = 0x3b, + UnstructuredSSRequest = 0x3c, + UnstructuredSSNotify = 0x3d + }; + + private: + + OperationCode mOperationCode; + void setValue () {mOperationCode = (OperationCode)mValue;} + + public: + + L3NonCallSSOperationCode(OperationCode wOperationCode = ProcessUnstructuredSSRequest) + :L3NonCallSSElementOctetLength(wOperationCode), + mOperationCode(wOperationCode) + {} + + void text(std::ostream& os) const; + OperationCode NonCallSSOperationCode() const {return mOperationCode;} + +}; + +class L3NonCallSSErrorCode : public L3NonCallSSElementOctetLength { + + public: + + enum ErrorCode { + SystemFailure = 0x22, + DataMissing = 0x23, + UnexpectedDataValue = 0x24, + UnknownAlphabet = 0x47, + CallBarred = 0xd, + AbsentSubscriber = 0x1b, + IllegalSubscriber = 0x9, + IllegalEquipment = 0xc, + UssdBusy = 0x48 + }; + + private: + + ErrorCode mErrorCode; + void setValue () {mErrorCode = (ErrorCode)mValue;} + + public: + + L3NonCallSSErrorCode(ErrorCode wErrorCode = SystemFailure) + :L3NonCallSSElementOctetLength(wErrorCode), + mErrorCode(wErrorCode) + {} + + void text(std::ostream& os) const {os << mErrorCode;} + ErrorCode NonCallSSErrorCode() const {return mErrorCode;} + +}; + +class L3NonCallSSProblemCodeTag : public L3NonCallSSElementOctetLength { + + public: + + /** GSM 04.80, Table 3.13 */ + enum ProblemCodeTag { + GeneralProblemTag = 0x80, + InvokeProblemTag = 0x81, + ReturnResultProblemTag = 0x82, + ReturnErrorProblemTag =0x83 + }; + + private: + + ProblemCodeTag mProblemCodeTag; + void setValue () {mProblemCodeTag = (ProblemCodeTag)mValue;} + + public: + + L3NonCallSSProblemCodeTag(ProblemCodeTag wProblemCodeTag = GeneralProblemTag) + :L3NonCallSSElementOctetLength(wProblemCodeTag), + mProblemCodeTag(wProblemCodeTag) + {} + + void text(std::ostream& os) const {os << mProblemCodeTag;} + ProblemCodeTag NonCallSSProblemCodeTag() const {return mProblemCodeTag;} + +}; + +class L3NonCallSSProblemCode : public L3NonCallSSElementOctetLength { + + public: + /** GSM 04.80, Table 3.14 - 3.17 */ + enum ProblemCode { + DuplicateInvokeID = 0x0, + UnrecognizedOperation = 0x1, + MistypedParameter = 0x2, + ResourceLimitation = 0x3, + InitiatingRelease = 0x4, + UnrecognizedLinkedID = 0x5, + LinkedResponseUnexpected = 0x6, + UnexpectedLinkedOperation = 0x7 + }; + + private: + + ProblemCode mProblemCode; + void setValue () {mProblemCode = (ProblemCode)mValue;} + + public: + + L3NonCallSSProblemCode(ProblemCode wProblemCode = DuplicateInvokeID) + :L3NonCallSSElementOctetLength(wProblemCode), + mProblemCode(wProblemCode) + {} + + void text(std::ostream& os) const {os << mProblemCode;} + ProblemCode NonCallSSProblemCode() const {return mProblemCode;} + +}; + +class L3NonCallSSVersionIndicator : public L3NonCallSSElementOctetLength { + + public: + + enum VersionIndicator { + Indicator1 = 0x0, + Indicator2 = 0x1 + }; + + private: + + VersionIndicator mVersionIndicator; + void setValue () {mVersionIndicator = (VersionIndicator)mValue;} + + public: + + L3NonCallSSVersionIndicator(VersionIndicator wVersionIndicator = Indicator1) + :L3NonCallSSElementOctetLength(wVersionIndicator), + mVersionIndicator(wVersionIndicator) + {} + + void text(std::ostream& os) const {os << mVersionIndicator;} + VersionIndicator NonCallSSVersionIndicator() const {return mVersionIndicator;} + +}; + +class L3NonCallSSInvokeID : public L3NonCallSSElementUndefLength { + + public: + L3NonCallSSInvokeID (uint64_t wValue = 1) + :L3NonCallSSElementUndefLength(wValue) + {} + +}; + +class L3NonCallSSLinkedID : public L3NonCallSSElementUndefLength { + + public: + L3NonCallSSLinkedID (uint64_t wValue = 0) + :L3NonCallSSElementUndefLength(wValue) + {} + +}; + +class L3NonCallSSCause : public L3NonCallSSElementUndefLength { + + public: + L3NonCallSSCause (uint64_t wValue = 0) + :L3NonCallSSElementUndefLength(wValue) + {} + +}; + +class L3NonCallSSLengthField : public L3ProtocolElement { + + protected: + + uint64_t mValue; + + public: + + L3NonCallSSLengthField(uint64_t wValue = 0) + :L3ProtocolElement(), + mValue(wValue) + {} + + size_t lengthV() const; + void writeV( L3Frame& dest, size_t &wp) const; + void parseV(const L3Frame& src, size_t& rp); + void parseV(const L3Frame&, size_t&, size_t) { abort(); } + void text(std::ostream& os) const {os << mValue;} + uint64_t value() const { return mValue; } + void setValue (uint64_t value) {mValue = value;} + +}; + +class L3NonCallSSParameters : public L3ProtocolElement { + + private: + + unsigned mDataCodingScheme; ///< data coding scheme + char mData[184]; ///< actual data, as a C string + L3NonCallSSLengthField mSequenceLength; + L3NonCallSSLengthField mDataLength; + unsigned mAlertingPattern; + bool mHaveAlertingPattern; + + public: + + L3NonCallSSParameters(unsigned wDataCodingScheme=0xF) + :L3ProtocolElement(), + mDataCodingScheme(wDataCodingScheme), + mSequenceLength(L3NonCallSSLengthField()), + mDataLength(L3NonCallSSLengthField()), + mAlertingPattern(0), + mHaveAlertingPattern(false) + { mData[0]='\0'; } + + /** Initize from a simple C string. */ + L3NonCallSSParameters(const char* text) + :L3ProtocolElement(), + mDataCodingScheme(0xF), + mSequenceLength(L3NonCallSSLengthField()), + mDataLength(L3NonCallSSLengthField()), + mAlertingPattern(0), + mHaveAlertingPattern(false) + { strncpy(mData,text,182); + mData[sizeof(mData) - 1] = '\0';} + + void DataCodingScheme(unsigned wDataCodingScheme) { mDataCodingScheme=wDataCodingScheme; } + unsigned DataCodingScheme() { return mDataCodingScheme; } + void alertingPattern (unsigned AlertingPattern) {mAlertingPattern = AlertingPattern; mHaveAlertingPattern = true;} + const char* data() const { return mData; } + const unsigned& alertingPattern() const {assert(mHaveAlertingPattern); return mAlertingPattern;} + bool haveAlertingPattern() const {return mHaveAlertingPattern;} + size_t lengthV() const { abort(); } + size_t length(); + void parseV(const L3Frame&, size_t&, size_t) { abort(); } + void parseV(const L3Frame&, size_t&); + + void writeV(L3Frame&, size_t&) const { abort(); } + void write(L3Frame&, size_t&); + void text(std::ostream&) const; +}; +} +#endif diff --git a/public-trunk/GSM/GSML3NonCallSSMessages.cpp b/public-trunk/GSM/GSML3NonCallSSMessages.cpp new file mode 100644 index 0000000..b012884 --- /dev/null +++ b/public-trunk/GSM/GSML3NonCallSSMessages.cpp @@ -0,0 +1,211 @@ +/** @file Messages for call independent Supplementary Service Control, GSM 04.80 2.2. */ + +/* +* Copyright 2008, 2009 Free Software Foundation, Inc. +* +* This software is distributed under the terms of the GNU Public License. +* See the COPYING file in the main directory for details. +* +* This use of this software may be subject to additional restrictions. +* See the LEGAL file in the main directory for details. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + + +#include +#include "GSML3NonCallSSMessages.h" +#include + + +using namespace std; +using namespace GSM; + + +ostream& operator<<(ostream& os, const L3NonCallSSMessage& msg) +{ + msg.text(os); + return os; +} + +ostream& GSM::operator<<(ostream& os, L3NonCallSSMessage::MessageType val) +{ + switch (val) { + case L3NonCallSSMessage::ReleaseComplete: + os << "ReleaseComplete"; break; + case L3NonCallSSMessage::Facility: + os << "Facility"; break; + case L3NonCallSSMessage::Register: + os << "Register"; break; + default: os << hex << "0x" << (int)val << dec; + } + return os; +} + +L3NonCallSSMessage * GSM::L3NonCallSSFactory(L3NonCallSSMessage::MessageType MTI) +{ + LOG(DEBUG) << "Factory MTI"<< (int)MTI; + switch (MTI) { + case L3NonCallSSMessage::Facility: return new L3NonCallSSFacilityMessage(); + case L3NonCallSSMessage::Register: return new L3NonCallSSRegisterMessage(); + case L3NonCallSSMessage::ReleaseComplete: return new L3NonCallSSReleaseCompleteMessage(); + default: { + //LOG(NOTICE) << "no L3 NonCallSS factory support for message "<< MTI; + return NULL; + } + } +} + +L3NonCallSSMessage * GSM::parseL3NonCallSS(const L3Frame& source) +{ + // mask out bit #7 (1011 1111) so use 0xbf + L3NonCallSSMessage::MessageType MTI = (L3NonCallSSMessage::MessageType)(0xbf & source.MTI()); + LOG(DEBUG) << "MTI= "<< (int)MTI; + L3NonCallSSMessage *retVal = L3NonCallSSFactory(MTI); + if (retVal==NULL) return NULL; + retVal->TIValue(source.TIValue()); + retVal->TIFlag(source.TIFlag()); + retVal->parse(source); + LOG(DEBUG) << "parse L3 Non Call SS Message" << *retVal; + return retVal; +} + +void L3NonCallSSMessage::write(L3Frame& dest) const +{ + // We override L3Message::write for the transaction identifier. + size_t l3len = bitsNeeded(); + if (dest.size()!=l3len) dest.resize(l3len); + size_t wp = 0; + dest.writeField(wp,mTIFlag,1); + dest.writeField(wp,mTIValue,3); + dest.writeField(wp,PD(),4); + dest.writeField(wp,MTI(),8); + writeBody(dest,wp); +} + +void L3NonCallSSMessage::text(ostream& os) const +{ + os << " MessageType = " <<(MessageType) MTI(); + os << " TI = (" << mTIFlag << "," << mTIValue << ")"; +} + +void L3NonCallSSFacilityMessage::writeBody( L3Frame &dest, size_t &wp ) const +{ + dest.writeField(wp,mL3NonCallSSComponent->length(),8); + mL3NonCallSSComponent->write(dest, wp); +} + +void L3NonCallSSFacilityMessage::parseBody( const L3Frame &src, size_t &rp ) +{ + rp+=8; + mL3NonCallSSComponent = parseL3NonCallSSComponent(src, rp); +} + +void L3NonCallSSFacilityMessage::text(ostream& os) const +{ + L3NonCallSSMessage::text(os); + os << " L3NonCallSSComponent = (" << *mL3NonCallSSComponent << ")"; +} + +void L3NonCallSSRegisterMessage::writeBody( L3Frame &dest, size_t &wp ) const +{ + dest.writeField(wp,0x1c,8); + dest.writeField(wp,mL3NonCallSSComponent->length(),8); + mL3NonCallSSComponent->write(dest, wp); +} + +void L3NonCallSSRegisterMessage::parseBody( const L3Frame &src, size_t &rp ) +{ + rp+=16; + mL3NonCallSSComponent = parseL3NonCallSSComponent(src, rp); + if((src.length() > mL3NonCallSSComponent->length()+2) && (src.readField(rp,8) == 0x7f)) + { + rp+=8; + mSSVersionIndicator.parseV(src, rp); + mHaveSSVersionIndicator = true; + } +} + +size_t L3NonCallSSRegisterMessage::bodyLength() const +{ + size_t bodyLength; + bodyLength = mL3NonCallSSComponent->length()+2; + if(mHaveSSVersionIndicator) bodyLength+=3; + return bodyLength; +} + +void L3NonCallSSRegisterMessage::text(ostream& os) const +{ + L3NonCallSSMessage::text(os); + os << " L3NonCallSSComponent = (" << *mL3NonCallSSComponent<< ")"; + if(mHaveSSVersionIndicator) os << " L3SSVersionIndicator = " << mSSVersionIndicator; +} + +void L3NonCallSSReleaseCompleteMessage::writeBody( L3Frame &dest, size_t &wp ) const +{ + if(mHaveCause) + { + dest.writeField(wp,0x08,8); + dest.writeField(wp,mCause.lengthV(),8); + mCause.writeV(dest, wp); + } + if(mHaveL3NonCallSSComponent) + { + dest.writeField(wp,0x1c,8); + dest.writeField(wp,mL3NonCallSSComponent->length(),8); + mL3NonCallSSComponent->write(dest, wp); + } +} + +void L3NonCallSSReleaseCompleteMessage::parseBody( const L3Frame &src, size_t &rp ) +{ + + if (src.length()>2) + { + if(mCause.parseTLV(0x08, src,rp)) + { + mHaveCause = true; + if ((src.length() > mCause.lengthTLV()+2)&&(src.readField(rp,8) == 0x1c)) + { + rp+=8; + mL3NonCallSSComponent = parseL3NonCallSSComponent(src, rp); + mHaveL3NonCallSSComponent = true; + } + } + else if (src.readField(rp,8) == 0x1c) + { + rp+=8; + mL3NonCallSSComponent = parseL3NonCallSSComponent(src, rp); + mHaveL3NonCallSSComponent = true; + } + } +} + +size_t L3NonCallSSReleaseCompleteMessage::bodyLength() const +{ + size_t bodyLength = 0; + if(mHaveCause) bodyLength+=mCause.lengthTLV(); + if(mHaveL3NonCallSSComponent) bodyLength+=mL3NonCallSSComponent->length()+2; + return bodyLength; +} + +void L3NonCallSSReleaseCompleteMessage::text(ostream& os) const +{ + L3NonCallSSMessage::text(os); + if(mHaveL3NonCallSSComponent) os << " L3NonCallSSComponent = (" << *mL3NonCallSSComponent << ")"; + if(mHaveCause) os << " L3Cause = " << mCause; +} + diff --git a/public-trunk/GSM/GSML3NonCallSSMessages.h b/public-trunk/GSM/GSML3NonCallSSMessages.h new file mode 100644 index 0000000..6946a68 --- /dev/null +++ b/public-trunk/GSM/GSML3NonCallSSMessages.h @@ -0,0 +1,187 @@ +/**@file Messages for call independent Supplementary Service Control, GSM 04.80 2.2. */ + +/* +* Copyright 2008, 2009 Free Software Foundation, Inc. +* +* This software is distributed under the terms of the GNU Public License. +* See the COPYING file in the main directory for details. +* +* This use of this software may be subject to additional restrictions. +* See the LEGAL file in the main directory for details. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +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. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + + +#ifndef GSML3NONCALLSSMESSAGES_H +#define GSML3NONCALLSSMESSAGES_H + +#include "GSMCommon.h" +#include "GSML3Message.h" +#include "GSML3NonCallSSElements.h" +#include "GSML3NonCallSSComponents.h" + + + +namespace GSM { + +/** +This a virtual class for L3 Messages for call independent Supplementary Service Control. +These messages are defined in GSM 04.80 2.2. +*/ +class L3NonCallSSMessage : public L3Message { + + private: + + unsigned mTIValue; ///< short transaction ID, GSM 04.07 11.2.3.1.3. + unsigned mTIFlag; ///< 0 for originating side, see GSM 04.07 11.2.3.1.3. + + public: + + /** GSM 04.80, Table 3.1 */ + enum MessageType { + /**@name Clearing message */ + //@{ + ReleaseComplete=0x2a, + //@} + /**@name Miscellaneous message group */ + //@{ + Facility=0x3a, + Register=0x3b + //@} + }; + + L3NonCallSSMessage(unsigned wTIFlag, unsigned wTIValue) + :L3Message(),mTIValue(wTIValue),mTIFlag(wTIFlag) + {} + + /** Override the write method to include transaction identifiers in header. */ + void write(L3Frame& dest) const; + L3PD PD() const { return L3NonCallSSPD; } + unsigned TIValue() const { return mTIValue; } + void TIValue(unsigned wTIValue) { mTIValue = wTIValue; } + unsigned TIFlag() const { return mTIFlag; } + void TIFlag(unsigned wTIFlag) { mTIFlag = wTIFlag; } + void text(std::ostream&) const; + +}; + +std::ostream& operator<<(std::ostream& os, const GSM::L3NonCallSSComponent& msg); +std::ostream& operator<<(std::ostream& os, L3NonCallSSMessage::MessageType MTI); + + + +/** +Parse a complete L3 call independent supplementary service control message into its object type. +@param source The L3 bits. +@return A pointer to a new message or NULL on failure. +*/ +L3NonCallSSMessage* parseL3NonCallSS(const L3Frame& source); + +/** +A Factory function to return a L3NonCallSSMessage of the specified MTI. +Returns NULL if the MTI is not supported. +*/ +L3NonCallSSMessage* L3NonCallSSFactory(L3NonCallSSMessage::MessageType MTI); + +/** Facility Message GSM 04.80 2.3. */ +class L3NonCallSSFacilityMessage : public L3NonCallSSMessage { + + private: + + L3NonCallSSComponent* mL3NonCallSSComponent; + + public: + + L3NonCallSSFacilityMessage(unsigned wTIFlag = 0, unsigned wTIValue = 7, + L3NonCallSSComponent* wL3NonCallSSComponent = NULL) + :L3NonCallSSMessage(wTIFlag,wTIValue), + mL3NonCallSSComponent (wL3NonCallSSComponent) + {} + + L3NonCallSSComponent* l3NonCallSSComponent() const {return mL3NonCallSSComponent;} + int MTI() const { return Facility; } + void writeBody( L3Frame &dest, size_t &wp ) const; + void parseBody( const L3Frame &src, size_t &rp ); + size_t bodyLength() const {return mL3NonCallSSComponent->length()+1;} + void text(std::ostream& os) const; + +}; + +/** Register Message GSM 04.80 2.4. */ +class L3NonCallSSRegisterMessage : public L3NonCallSSMessage { + + private: + + L3NonCallSSComponent* mL3NonCallSSComponent; + L3NonCallSSVersionIndicator mSSVersionIndicator; + bool mHaveSSVersionIndicator; + + public: + + L3NonCallSSRegisterMessage(unsigned wTIFlag = 0, unsigned wTIValue = 7, + L3NonCallSSComponent* wL3NonCallSSComponent = NULL) + :L3NonCallSSMessage(wTIFlag,wTIValue), + mL3NonCallSSComponent (wL3NonCallSSComponent), + mHaveSSVersionIndicator(false) + {} + + L3NonCallSSComponent* l3NonCallSSComponent() const {return mL3NonCallSSComponent;} + const L3NonCallSSVersionIndicator& SSVersionIndicator() const {assert(mHaveSSVersionIndicator); return mSSVersionIndicator;} + bool haveL3NonCallSSVersionIndicator() const {return mHaveSSVersionIndicator;} + int MTI() const { return Register; } + void writeBody( L3Frame &dest, size_t &wp ) const; + void parseBody( const L3Frame &src, size_t &rp ); + size_t bodyLength() const; + void text(std::ostream&) const; + +}; + +/** Release Complete Message GSM 04.80 2.5. */ +class L3NonCallSSReleaseCompleteMessage : public L3NonCallSSMessage { + + private: + + L3NonCallSSComponent* mL3NonCallSSComponent; + bool mHaveL3NonCallSSComponent; + L3NonCallSSCause mCause; + bool mHaveCause; + + public: + + L3NonCallSSReleaseCompleteMessage(unsigned wTIFlag = 0, unsigned wTIValue = 7) + :L3NonCallSSMessage(wTIFlag,wTIValue), + mHaveL3NonCallSSComponent(false), + mHaveCause(false) + {} + + void component (L3NonCallSSComponent* Component) {mL3NonCallSSComponent = Component; mHaveL3NonCallSSComponent = true;} + void cause (L3NonCallSSCause Cause) {mCause = Cause; mHaveCause = true;} + + L3NonCallSSComponent* l3NonCallSSComponent() const {assert(mHaveL3NonCallSSComponent); return mL3NonCallSSComponent;} + bool haveL3NonCallSSComponent() const {return mHaveL3NonCallSSComponent;} + const L3NonCallSSCause& l3NonCallSSCause() const {assert(mHaveCause); return mCause;} + bool haveL3NonCallSSCause() const {return mHaveCause;} + int MTI() const { return ReleaseComplete; } + void writeBody( L3Frame &dest, size_t &wp ) const; + void parseBody( const L3Frame &src, size_t &rp ); + size_t bodyLength() const; + void text(std::ostream&) const; + +}; + +} +#endif diff --git a/public-trunk/GSM/Makefile.am b/public-trunk/GSM/Makefile.am index 9f116da..bcb3b35 100644 --- a/public-trunk/GSM/Makefile.am +++ b/public-trunk/GSM/Makefile.am @@ -37,6 +37,9 @@ libGSM_la_SOURCES = \ GSML3Message.cpp \ GSML3MMElements.cpp \ GSML3MMMessages.cpp \ + GSML3NonCallSSComponents.cpp \ + GSML3NonCallSSElements.cpp \ + GSML3NonCallSSMessages.cpp \ GSML3RRElements.cpp \ GSML3RRMessages.cpp \ GSMLogicalChannel.cpp \ @@ -58,6 +61,9 @@ noinst_HEADERS = \ GSML3Message.h \ GSML3MMElements.h \ GSML3MMMessages.h \ + GSML3NonCallSSComponents.h \ + GSML3NonCallSSElements.h \ + GSML3NonCallSSMessages.h \ GSML3RRElements.h \ GSML3RRMessages.h \ GSMLogicalChannel.h \ diff --git a/public-trunk/GSM/Makefile.in b/public-trunk/GSM/Makefile.in index 3b5ddf1..3a5c203 100644 --- a/public-trunk/GSM/Makefile.in +++ b/public-trunk/GSM/Makefile.in @@ -96,6 +96,7 @@ am_libGSM_la_OBJECTS = GSM610Tables.lo GSMCommon.lo GSMConfig.lo \ GSML1FEC.lo GSML2LAPDm.lo GSML3CCElements.lo \ GSML3CCMessages.lo GSML3CommonElements.lo GSML3Message.lo \ GSML3MMElements.lo GSML3MMMessages.lo GSML3RRElements.lo \ + GSML3NonCallSSComponents.lo GSML3NonCallSSElements.lo GSML3NonCallSSMessages.lo \ GSML3RRMessages.lo GSMLogicalChannel.lo GSMSAPMux.lo \ GSMTDMA.lo GSMTransfer.lo GSMTAPDump.lo PowerManager.lo libGSM_la_OBJECTS = $(am_libGSM_la_OBJECTS) @@ -282,6 +283,9 @@ libGSM_la_SOURCES = \ GSML3Message.cpp \ GSML3MMElements.cpp \ GSML3MMMessages.cpp \ + GSML3NonCallSSComponents.cpp \ + GSML3NonCallSSElements.cpp \ + GSML3NonCallSSMessages.cpp \ GSML3RRElements.cpp \ GSML3RRMessages.cpp \ GSMLogicalChannel.cpp \ @@ -303,6 +307,9 @@ noinst_HEADERS = \ GSML3Message.h \ GSML3MMElements.h \ GSML3MMMessages.h \ + GSML3NonCallSSComponents.h \ + GSML3NonCallSSElements.h \ + GSML3NonCallSSMessages.h \ GSML3RRElements.h \ GSML3RRMessages.h \ GSMLogicalChannel.h \ @@ -374,6 +381,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GSML3CommonElements.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GSML3MMElements.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GSML3MMMessages.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GSML3NonCallSSComponents.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GSML3NonCallSSElements.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GSML3NonCallSSMessages.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GSML3Message.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GSML3RRElements.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GSML3RRMessages.Plo@am__quote@ diff --git a/public-trunk/apps/OpenBTS.config.example b/public-trunk/apps/OpenBTS.config.example index bd09446..bd650fb 100644 --- a/public-trunk/apps/OpenBTS.config.example +++ b/public-trunk/apps/OpenBTS.config.example @@ -177,6 +177,21 @@ SMS.DefaultDestSMSC 0000 #SMS.HTTP.AccessString sendmsg?user=xxxx&password=xxxx&api_id=xxxx +# +# USSD parameters +# +# USSD timeout for waiting MS response +USSD.timeout 100000 + +# USSD MO Handler (HTTP, CLI or Test) +USSD.Handler.MO CLI + +# The USSD HTTP gateway. +USSD.HTTP.Gateway api.clickatell.com + +# IF USSD.HTTP.Gateway IS DEFINED, USSD.HTTP.AccessString MUST ALSO BE DEFINED. +USSD.HTTP.AccessString sendmsg?user=xxxx&password=xxxx&api_id=xxxx + # Things to query during registration updates.