170 lines
4.9 KiB
C++
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;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|