OpenBTS-UMTS/Control/ControlCommon.cpp

170 lines
4.9 KiB
C++

/**@file Common-use functions for the control layer. */
/*
* OpenBTS provides an open source alternative to legacy telco protocols and
* traditionally complex, proprietary hardware systems.
*
* Copyright 2008, 2010 Free Software Foundation, Inc.
* Copyright 2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero General
* Public License version 3. See the COPYING and NOTICE files in the main
* directory for licensing information.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
*/
#include "ControlCommon.h"
#include "TransactionTable.h"
#include <GSML3Message.h>
#include <GSML3CCMessages.h>
#include <GSML3RRMessages.h>
#include <GSML3MMMessages.h>
#include <UMTSLogicalChannel.h>
#include <SIPEngine.h>
#include <SIPInterface.h>
#include <Logger.h>
#undef WARNING
using namespace std;
using namespace Control;
// FIXME -- getMessage should return an L3Frame, not an L3Message.
// This will mean moving all of the parsing into the control layer.
// FIXME -- This needs an adjustable timeout.
GSM::L3Message* Control::getMessage(UMTS::LogicalChannel *LCH, unsigned SAPI)
{
// FIXME -- We need to set a proper timeout here.
unsigned timeout_ms = 20000;
GSM::L3Frame *rcv = LCH->recv(timeout_ms,SAPI);
if (rcv==NULL) {
LOG(NOTICE) << "timeout";
throw ChannelReadTimeout();
}
LOG(DEBUG) << "received " << *rcv;
GSM::Primitive primitive = rcv->primitive();
if (primitive!=GSM::DATA) {
LOG(NOTICE) << "unexpected primitive " << primitive;
delete rcv;
throw UnexpectedPrimitive();
}
GSM::L3Message *msg = GSM::parseL3(*rcv);
delete rcv;
if (msg==NULL) {
LOG(NOTICE) << "unparsed message";
throw UnsupportedMessage();
}
return msg;
}
/* Resolve a mobile ID to an IMSI and return TMSI if it is assigned. */
unsigned Control::resolveIMSI(bool sameLAI, GSM::L3MobileIdentity& mobileID, UMTS::LogicalChannel* LCH)
{
// Returns known or assigned TMSI.
assert(LCH);
LOG(DEBUG) << "resolving mobile ID " << mobileID << ", sameLAI: " << sameLAI;
// IMSI already? See if there's a TMSI already, too.
if (mobileID.type()==GSM::IMSIType) return gTMSITable.TMSI(mobileID.digits());
// IMEI? WTF?!
// FIXME -- Should send MM Reject, cause 0x60, "invalid mandatory information".
if (mobileID.type()==GSM::IMEIType) throw UnexpectedMessage();
// Must be a TMSI.
// Look in the table to see if it's one we assigned.
unsigned TMSI = mobileID.TMSI();
char* IMSI = NULL;
if (sameLAI) IMSI = gTMSITable.IMSI(TMSI);
if (IMSI) {
// We assigned this TMSI already; the TMSI/IMSI pair is already in the table.
mobileID = GSM::L3MobileIdentity(IMSI);
LOG(DEBUG) << "resolving mobile ID (table): " << mobileID;
free(IMSI);
return TMSI;
}
// Not our TMSI.
// Phones are not supposed to do this, but many will.
// If the IMSI's not in the table, ASK for it.
LCH->send(GSM::L3IdentityRequest(GSM::IMSIType));
// FIXME -- This request times out on T3260, 12 sec. See GSM 04.08 Table 11.2.
GSM::L3Message* msg = getMessage(LCH);
GSM::L3IdentityResponse *resp = dynamic_cast<GSM::L3IdentityResponse*>(msg);
if (!resp) {
if (msg) delete msg;
throw UnexpectedMessage();
}
mobileID = resp->mobileID();
LOG(INFO) << resp;
delete msg;
LOG(DEBUG) << "resolving mobile ID (requested): " << mobileID;
// FIXME -- Should send MM Reject, cause 0x60, "invalid mandatory information".
if (mobileID.type()!=GSM::IMSIType) throw UnexpectedMessage();
// Return 0 to indicate that we have not yet assigned our own TMSI for this phone.
return 0;
}
/* Resolve a mobile ID to an IMSI. */
void Control::resolveIMSI(GSM::L3MobileIdentity& mobileIdentity, UMTS::LogicalChannel* LCH)
{
// Are we done already?
if (mobileIdentity.type()==GSM::IMSIType) return;
// If we got a TMSI, find the IMSI.
if (mobileIdentity.type()==GSM::TMSIType) {
char *IMSI = gTMSITable.IMSI(mobileIdentity.TMSI());
if (IMSI) mobileIdentity = GSM::L3MobileIdentity(IMSI);
free(IMSI);
}
// Still no IMSI? Ask for one.
if (mobileIdentity.type()!=GSM::IMSIType) {
LOG(NOTICE) << "MOC with no IMSI or valid TMSI. Reqesting IMSI.";
LCH->send(GSM::L3IdentityRequest(GSM::IMSIType));
// FIXME -- This request times out on T3260, 12 sec. See GSM 04.08 Table 11.2.
GSM::L3Message* msg = getMessage(LCH);
GSM::L3IdentityResponse *resp = dynamic_cast<GSM::L3IdentityResponse*>(msg);
if (!resp) {
if (msg) delete msg;
throw UnexpectedMessage();
}
mobileIdentity = resp->mobileID();
delete msg;
}
// Still no IMSI??
if (mobileIdentity.type()!=GSM::IMSIType) {
// FIXME -- This is quick-and-dirty, not following GSM 04.08 5.
LOG(WARNING) << "MOC setup with no IMSI";
// Cause 0x60 "Invalid mandatory information"
LCH->send(GSM::L3CMServiceReject(GSM::L3RejectCause(0x60)));
LCH->send(GSM::L3ChannelRelease());
// The SIP side and transaction record don't exist yet.
// So we're done.
return;
}
}