/* * OpenBTS provides an open source alternative to legacy telco protocols and * traditionally complex, proprietary hardware systems. * * Copyright 2008, 2009, 2010 Free Software Foundation, Inc. * Copyright 2010 Kestrel Signal Processing, 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 "TMSITable.h" #include #include #include #include #include #include #include #include using namespace std; using namespace Control; static const char* createTMSITable = { "CREATE TABLE IF NOT EXISTS TMSI_TABLE (" "TMSI INTEGER PRIMARY KEY AUTOINCREMENT, " "CREATED INTEGER NOT NULL, " // Unix time of record creation "ACCESSED INTEGER NOT NULL, " // Unix time of last encounter "APP_FLAGS INTEGER DEFAULT 0, " // Application-specific flags "IMSI TEXT UNIQUE NOT NULL, " // IMSI "IMEI TEXT, " // IMEI "L3TI INTEGER DEFAULT 0," // L3 transaction identifier "A5_SUPPORT INTEGER, " // encryption support "POWER_CLASS INTEGER, " // power class "OLD_TMSI INTEGER, " // previous TMSI in old network "PREV_MCC INTEGER, " // previous network MCC "PREV_MNC INTEGER, " // previous network MNC "PREV_LAC INTEGER, " // previous network LAC "RANDUPPER INTEGER, " // authentication token "RANDLOWER INTEGER, " // authentication token "SRES INTEGER, " // authentication token "DEG_LAT FLOAT, " // RRLP result "DEG_LONG FLOAT, " // RRLP result "kc varchar(33) default '' " ")" }; TMSITable::TMSITable(const char* wPath) { int rc = sqlite3_open(wPath,&mDB); if (rc) { // The LOG() below is going to crash, so lets make sure we print something out: std::cout << "Cannot open TMSITable database at " << wPath; LOG(EMERG) << "Cannot open TMSITable database at " << wPath << ": " << sqlite3_errmsg(mDB); sqlite3_close(mDB); mDB = NULL; return; } if (!sqlite3_command(mDB,createTMSITable)) { LOG(EMERG) << "Cannot create TMSI table"; } } TMSITable::~TMSITable() { if (mDB) sqlite3_close(mDB); } unsigned TMSITable::assign(const char* IMSI, const GSM::L3LocationUpdatingRequest* lur) { // Create or find an entry based on IMSI. // Return assigned TMSI. assert(mDB); LOG(DEBUG) << "IMSI=" << IMSI; // Is there already a record? unsigned TMSI; if (sqlite3_single_lookup(mDB,"TMSI_TABLE","IMSI",IMSI,"TMSI",TMSI)) { LOG(DEBUG) << "found TMSI " << TMSI; touch(TMSI); return TMSI; } // Create a new record. LOG(NOTICE) << "new entry for IMSI " << IMSI; char query[1000]; unsigned now = (unsigned)time(NULL); if (!lur) { sprintf(query, "INSERT INTO TMSI_TABLE (IMSI,CREATED,ACCESSED) " "VALUES ('%s',%u,%u)", IMSI,now,now); } else { const GSM::L3LocationAreaIdentity &lai = lur->LAI(); const GSM::L3MobileIdentity &mid = lur->mobileID(); if (mid.type()==GSM::TMSIType) { sprintf(query, "INSERT INTO TMSI_TABLE (IMSI,CREATED,ACCESSED,PREV_MCC,PREV_MNC,PREV_LAC,OLD_TMSI) " "VALUES ('%s',%u,%u,%u,%u,%u,%u)", IMSI,now,now,lai.MCC(),lai.MNC(),lai.LAC(),mid.TMSI()); } else { sprintf(query, "INSERT INTO TMSI_TABLE (IMSI,CREATED,ACCESSED,PREV_MCC,PREV_MNC,PREV_LAC) " "VALUES ('%s',%u,%u,%u,%u,%u)", IMSI,now,now,lai.MCC(),lai.MNC(),lai.LAC()); } } if (!sqlite3_command(mDB,query)) { LOG(ALERT) << "TMSI creation failed"; return 0; } if (!sqlite3_single_lookup(mDB,"TMSI_TABLE","IMSI",IMSI,"TMSI",TMSI)) { LOG(ERR) << "TMSI database inconsistancy"; return 0; } return TMSI; } void TMSITable::touch(unsigned TMSI) const { // Update timestamp. char query[100]; sprintf(query,"UPDATE TMSI_TABLE SET ACCESSED = %u WHERE TMSI == %u", (unsigned)time(NULL),TMSI); sqlite3_command(mDB,query); } // Returned string must be free'd by the caller. char* TMSITable::IMSI(unsigned TMSI) const { char* IMSI = NULL; if (sqlite3_single_lookup(mDB,"TMSI_TABLE","TMSI",TMSI,"IMSI",IMSI)) touch(TMSI); return IMSI; } unsigned TMSITable::TMSI(const char* IMSI) const { unsigned TMSI=0; if (sqlite3_single_lookup(mDB,"TMSI_TABLE","IMSI",IMSI,"TMSI",TMSI)) touch(TMSI); return TMSI; } void printAge(unsigned seconds, ostream& os) { static const unsigned k=5; os << setw(4); if (seconds