tbf: Clean old MS objects if they have the same TLLI

Currently if an MS retries to access the PCU by using RACH and if
there is already an entry for that MS, a duplicated MS object
referring to the same TLLI is created. This is caused by blindly
setting the TLLI without querying the MS storage to avoid
inconsitencies.

This leads to several entries in the MS storage that are assigned to
the same TLLI. If that happens, 'show ms all' can display multiple
entries with the same TLLI (note that an MS object can belong to
several TLLIs, so there might be an intersection that is not visible
in the list) or 'show tbf all' can show entries with MS_CLASS == 0 in
some cases.

This commit changes update_ms() to merge and clean up old entries
that belong to the given TLLI if they exist. Some data (like the MS
class) is copied to the new MS object.

Note that TBF belonging to the old MS object are deleted immediately
if they have not registered a timer.

Sponsored-by: On-Waves ehf
This commit is contained in:
Jacob Erlbeck 2015-08-16 18:19:32 +02:00
parent 3449a61032
commit 28c40b1757
4 changed files with 80 additions and 17 deletions

View File

@ -83,7 +83,8 @@ void gprs_rlcmac_tbf::assign_imsi(const char *imsi_)
"%s the IMSI '%s' was already assigned to another "
"MS object: TLLI = 0x%08x, that IMSI will be removed\n",
name(), imsi_, old_ms->tlli());
old_ms->set_imsi("");
merge_and_clear_ms(old_ms);
}
m_ms->set_imsi(imsi_);
@ -156,6 +157,49 @@ void gprs_rlcmac_tbf::set_ms(GprsMs *ms)
m_ms->attach_tbf(this);
}
void gprs_rlcmac_tbf::merge_and_clear_ms(GprsMs *old_ms)
{
if (old_ms == ms())
return;
GprsMs::Guard guard_old(old_ms);
if (strlen(ms()->imsi()) == 0 && strlen(old_ms->imsi()) != 0) {
ms()->set_imsi(old_ms->imsi());
old_ms->set_imsi("");
}
if (!ms()->ms_class() && old_ms->ms_class())
ms()->set_ms_class(old_ms->ms_class());
/* Clean up the old MS object */
/* TODO: Use timer? */
if (old_ms->ul_tbf() && old_ms->ul_tbf()->T == 0) {
if (old_ms->ul_tbf() == this) {
LOGP(DRLCMAC, LOGL_ERROR,
"%s is referred by the old MS "
"and will not be deleted\n",
name());
set_ms(NULL);
} else {
tbf_free(old_ms->ul_tbf());
}
}
if (old_ms->dl_tbf() && old_ms->dl_tbf()->T == 0) {
if (old_ms->dl_tbf() == this) {
LOGP(DRLCMAC, LOGL_ERROR,
"%s is referred by the old MS "
"and will not be deleted\n",
name());
set_ms(NULL);
} else {
tbf_free(old_ms->dl_tbf());
}
}
old_ms->reset();
}
void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
{
if (!ms())
@ -164,6 +208,18 @@ void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction di
if (!tlli)
return;
/* TODO: When the TLLI does not match the ms, check if there is another
* MS object that belongs to that TLLI and if yes make sure one of them
* gets deleted. This is the same problem that can arise with
* assign_imsi() so there should be a unified solution */
if (!ms()->check_tlli(tlli)) {
GprsMs *old_ms;
old_ms = bts->ms_store().get_ms(tlli, 0, NULL);
if (old_ms)
merge_and_clear_ms(old_ms);
}
if (dir == GPRS_RLCMAC_UL_TBF)
ms()->set_tlli(tlli);
else

View File

@ -226,6 +226,7 @@ protected:
gprs_rlcmac_bts *bts_data() const;
int extract_tlli(const uint8_t *data, const size_t len);
void merge_and_clear_ms(GprsMs *old_ms);
static const char *tbf_state_name[6];

View File

@ -388,18 +388,23 @@ static void test_tbf_imsi()
OSMO_ASSERT(ms1 == ms2);
/* use the same IMSI on TBF 2 */
dl_tbf[1]->assign_imsi("001001000000002");
ms1 = the_bts.ms_store().get_ms(0, 0, "001001000000002");
OSMO_ASSERT(ms1 != NULL);
OSMO_ASSERT(ms1 != ms2);
OSMO_ASSERT(strcmp(ms1->imsi(), "001001000000002") == 0);
OSMO_ASSERT(strcmp(ms2->imsi(), "") == 0);
{
GprsMs::Guard guard(ms2);
dl_tbf[1]->assign_imsi("001001000000002");
ms1 = the_bts.ms_store().get_ms(0, 0, "001001000000002");
OSMO_ASSERT(ms1 != NULL);
OSMO_ASSERT(ms1 != ms2);
OSMO_ASSERT(strcmp(ms1->imsi(), "001001000000002") == 0);
OSMO_ASSERT(strcmp(ms2->imsi(), "") == 0);
}
ms2 = the_bts.ms_store().get_ms(0xf1000001);
OSMO_ASSERT(ms2 == NULL);
tbf_free(dl_tbf[1]);
ms1 = the_bts.ms_store().get_ms(0, 0, "001001000000002");
OSMO_ASSERT(ms1 == NULL);
tbf_free(dl_tbf[0]);
printf("=== end %s ===\n", __func__);
}

View File

@ -462,19 +462,20 @@ The MS object cannot fully confirm an unexpected TLLI: 0xf1000002, partly confir
Modifying MS object, TLLI = 0xf1000001, IMSI '' -> '001001000000001'
Modifying MS object, TLLI = 0xf1000001, IMSI '001001000000001' -> '001001000000002'
TBF(TFI=1 TLLI=0xf1000002 DIR=DL STATE=FLOW) the IMSI '001001000000002' was already assigned to another MS object: TLLI = 0xf1000001, that IMSI will be removed
Modifying MS object, TLLI = 0xf1000001, IMSI '001001000000002' -> ''
Modifying MS object, TLLI = 0xf1000002, IMSI '' -> '001001000000002'
TBF(TFI=1 TLLI=0xf1000002 DIR=DL STATE=FLOW) free
TBF(TFI=1 TLLI=0xf1000002 DIR=DL STATE=FLOW) Software error: Pending downlink assignment. This may not happen, because the assignment message never gets transmitted. Please be sure not to free in this state. PLEASE FIX!
PDCH(TS 4, TRX 0): Detaching TBF(TFI=1 TLLI=0xf1000002 DIR=DL STATE=FLOW), 1 TBFs, USFs = 00, TFIs = 00000001.
Detaching TBF from MS object, TLLI = 0xf1000002, TBF = TBF(TFI=1 TLLI=0xf1000002 DIR=DL STATE=FLOW)
Destroying MS object, TLLI = 0xf1000002
********** TBF ends here **********
Modifying MS object, TLLI = 0xf1000001, IMSI '001001000000002' -> ''
TBF(TFI=0 TLLI=0xf1000001 DIR=DL STATE=FLOW) free
TBF(TFI=0 TLLI=0xf1000001 DIR=DL STATE=FLOW) Software error: Pending downlink assignment. This may not happen, because the assignment message never gets transmitted. Please be sure not to free in this state. PLEASE FIX!
PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xf1000001 DIR=DL STATE=FLOW), 0 TBFs, USFs = 00, TFIs = 00000000.
PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xf1000001 DIR=DL STATE=FLOW), 1 TBFs, USFs = 00, TFIs = 00000002.
Detaching TBF from MS object, TLLI = 0xf1000001, TBF = TBF(TFI=0 TLLI=0xf1000001 DIR=DL STATE=FLOW)
Destroying MS object, TLLI = 0xf1000001
********** TBF ends here **********
Clearing MS object, TLLI: 0xf1000001, IMSI: ''
Destroying MS object, TLLI = 0x00000000
TBF(TFI=1 TLLI=0xf1000002 DIR=DL STATE=FLOW) free
TBF(TFI=1 TLLI=0xf1000002 DIR=DL STATE=FLOW) Software error: Pending downlink assignment. This may not happen, because the assignment message never gets transmitted. Please be sure not to free in this state. PLEASE FIX!
PDCH(TS 4, TRX 0): Detaching TBF(TFI=1 TLLI=0xf1000002 DIR=DL STATE=FLOW), 0 TBFs, USFs = 00, TFIs = 00000000.
Detaching TBF from MS object, TLLI = 0xf1000002, TBF = TBF(TFI=1 TLLI=0xf1000002 DIR=DL STATE=FLOW)
Destroying MS object, TLLI = 0xf1000002
********** TBF ends here **********
********** TBF starts here **********
Allocating DL TBF: MS_CLASS=45